관리 메뉴

사과하는 제라스

11장. 컴포넌트 성능 최적화 본문

코테이토 동아리/[코테이토]React 스터디 5기

11장. 컴포넌트 성능 최적화

Xerath(제라스) 2023. 2. 3. 12:39

목차

    728x90
    반응형

    - useState 사용 시

    useState(func()) //이러면 리렌더링될 때마다 func함수가 호출됨.
    useState(func) //이런 식으로 파라미터를 함수 형태로 넣어주면 컴포넌트가 처음 렌더링딜 때만 func 함수 실행함.

    - 느려지는 원인 분석

    1. 자신이 전달받은 props가 변경될 때

    2. 자신의 state가 바뀔 때

    3. 부모 컴포넌트가 리렌더링될 때

    4. forceUpdate 함수가 실행될 때

     

    컴포넌트의 개수가 많은데 모두 리렌더링을 하게 되면 느려지는 이슈 발생

    -> 컴포넌트 리렌더링 성능을 최적화해줘야 함.

     

    1. React.memo를 활용

    import React from 'react';
    import {
      MdCheckBoxOutlineBlank,
      MdCheckBox,
      MdRemoveCircleOutline,
    } from 'react-icons/md';
    import './TodoListItem.scss';
    import cn from 'classnames';
    
    const TodoListItem = ({ todo, onRemove, onToggle, style }) => {
      const { id, text, checked } = todo;
      return (
        <div className="TodoListItem-virtualized" style={style}>
          <div className="TodoListItem">
            <div
              className={cn('checkbox', { checked })}
              onClick={() => onToggle(id)}
            >
              {checked ? <MdCheckBox /> : <MdCheckBoxOutlineBlank />}
              <div className="text">{text}</div>
            </div>
            <div className="remove" onClick={() => onRemove(id)}>
              <MdRemoveCircleOutline />
            </div>
          </div>
        </div>
      );
    };
    
    export default React.memo(TodoListItem); //이 부분처럼 처리해주면 됨.

    -> 이런 식으로 React.memo를 써주면 컴포넌트의 props(todo, onRemove, onToggle, style)가 변경되지 않을 시 리렌더링하지 않음.

    2. 함수가 바뀌지 않게 하기

    1) useState의 함수형 업데이트

    //이런 식으로 이전의 state(nowTodos)를 가지고 다음 state(nowTodos.concat(todo))를 선언해주면 됨.
    setTodo(nowTodos => nowTodos.concat(todo));

    2) useReducer 사용하기

    useReducer를 사용하면 상태를 업데이트하는 로직을 모아서 컴포넌트 바깥에 둘 수 있음.

    ...
    function createBulkTodos() {
      const array = [];
      for (let i = 1; i <= 2500; i++) {
        array.push({
          id: i,
          text: `Todo ${i}`,
          checked: false,
        });
      }
      return array;
    }
    
    function todoReducer(todos, action) {
      switch (action.type) {
        case 'INSERT':
          return action.tempTodos;
        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); //이때 두번째 파라미터는 initialState값임.
    
      const nextId = useRef(2501);
      const onInsert = useCallback(
        (text) => {
          const tempTodos = [...todos, { id: nextId, text, checked: false }];
          dispatch({ type: 'INSERT', tempTodos });
          nextId.current += 1;
        },
        [todos],
      );
      ...

    3. 불변성 유지하는 방법

    - 불변성을 지킨다: 기존의 값을 직접 수정하지 않으면서 새로운 값을 만들어 내는 것.

     

    //이런 방식으로 하면 얕은 복사만...!!
    const nextTodos = [...todos];
    
    
    //이렇게 하면 새로운 객체를 할당하게 됨.
    nextTodos[0] = {
    	...nextTodos[0],
        checked: false,
    };

    4. react-virtualized를 활용

    이게 뭔데?? 스크롤하기 전에 보이지 않는 컴포넌트들은 렌더링하지 않고 크기만 차지하게끔 하는 라이브러리.

     

     

     

    모든 작업에 최적화를 할 필요는 없음!

    하지만 보여줄 항목이 많아져서 업데이트가 종종 발생한다면 최적화 필요!

    728x90
    반응형