ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 컴포넌트 성능 최적화(함수형 업데이트, 리덕스)
    프론트엔드 2022. 8. 18. 14:50

    컴포넌트가 리렌더링하는 순간

    1. 자신이 전달받은 props가 변경될 때
    2. 자신의 stat가 바뀔 때
    3. 부모 컴포넌트가 리렌더링 될 때
    4. forceUpdate 함수가 실행될 때

    컴포넌트 2000개가 리렌더링 된다면? 앱의 성능이 급격히 저하된다.

    따라서 컴포넌트 리렌더링 성능을 최적화해줄 필요가 있다.

     

    1. React.memo : 컴포넌트의 props가 바뀌지 않았다면, 리렌더링을 하지 않도록 한다.

    const TodoList = ({ todos, onRemove }) => {
      return (
        <TodoListdesign>
          {todos.map((todo) => (
            <TodoListItem
              todo={todo}
              key={todo.user_key}
              onRemove={onRemove}
            ></TodoListItem>
          ))}
        </TodoListdesign>
      );
    };

    export default React.memo(TodoList); 컴포넌트를 만들고 감싸주기만 하면 된다.

     

    2. useState의 함수형 업데이트 : 함수가 계속 만들어지는 상황을 방지한다.

     const onInsert = useCallback(
        (content, createdDate) => {
          const todo = {
            id: nextId.current,
            content, //백엔드에서 받아온 데이터 이름
            createdDate, //백엔드에서 받아온 데이터 이름
          };
          setTodos(todos.concat(todo)); //todos라는 배열에 생성된 todo 삽입 이 부분을 바꾼다.
          nextId.current += 1;
        },
        [todos] 이 부분을 바꾼다.
      );

      const onRemove = useCallback(
        (id) => {
          setTodos(todos.filter((todo) => todo.id !== id)); 이 부분을 바꾼다.
        },
        [todos] 이 부분을 바꾼다.
      );
      const onInsert = useCallback(
        (content, createdDate) => {
          const todo = {
            id: nextId.current,
            content, //백엔드에서 받아온 데이터 이름
            createdDate, //백엔드에서 받아온 데이터 이름
          };
          setTodos(todos => todos.concat(todo)); //todos라는 배열에 생성된 todo 삽입
          nextId.current += 1;
        },
        []
      );

      const onRemove = useCallback(
        (id) => {
          setTodos(todos => todos.filter((todo) => todo.id !== id));
        },
        [
      );

    새로운 상태를 바로 파라미터로 넣는 대신, 상태 업데이트를 어떻게 업데이트할지 정의해주는 것이다. 그러면 useCallback 을 사용할 때 두번째 파라미터로 넣는 배열에 []처리해도 된다.

     

    3. useReducer : useState 함수형 업데이트를 사용하는 대신, 리듀서를 사용해도 함수가 계속 만들어지는 현상을 막을 수 있다.

    function todoReducer(todos, action) {
      switch (action.type) {
        case "INSERT":
          return todos.concat(action.todo);  useState의 함수형 업데이트 사용
        case "REMOVE":
          return todos.filter((todo) => todo.id !== action.id);  
        case "Toggle":
          return todos.map((todo) =>
            todo.id === action.id ? { ...todo, checked: !todo.checked } : todo
          );
        default:
          return todos;
      }
    }

    const App = () => {
      const [todos, dispatch] = useReducer(todoReducer, undefined, createBulkTodos);  3번째 파라미터에 초기값을 넣어줬다.
    두번째에 undefined를 쓰고 세번째에 초기값을 넣어주면 맨 처음 렌더링될 때만 createBulkTodos함수가 호출된다.

      const nextId = useRef(4);
      const onInsert = useCallback((content, createdDate) => {
        const todo = {
          id: nextId.current,
          content,
          createdDate,
          checked: false,
        };

        dispatch({ type: "INSERT", todo });  두번째 파라미터는 전달인자이다.
        nextId.current += 1;
      }, []);

      const onRemove = useCallback((id) => {
        dispatch({ type: "REMOVE", id });
      }, []);

      const onToggle = useCallback((id) => {
        dispatch({ type: "TOGGLE", id });
      }, []);


      return (
      <TodoTemplate>
              <TodoInsert onInsert={onInsert}></TodoInsert>
              <TodoList todos={todos} onRemove={onRemove} onToggle={onToggle} ></TodoList>
      </TodoTemplate>
      );
    };

    export default App;

     

    우리는 위코드를 보며 불변성을 유지하면서 상태를 업데이트하는 것이 왜 중요한지 배웠다. (성능 최적화)

     

    4. immer을 사용하지 않고 불변성 유지

     

    ...이어서

Designed by Tistory.