공부하기/React

[React] 컴포넌트 성능 최적화 : 많은 데이터 렌더링

다섯자두 2022. 2. 24. 17:32

다음 내용은 책 '리액트를 다루는 기술'을 바탕으로 작성된 글입니다.


 

컴포넌트는 다음과 같은 상황에서 리렌더링이 발생한다.

 

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

2. 자신의 state가 변경될 때

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

4. forceUpdate 함수가 실행될 때

 

리렌더링이 되지 않아도 되는 컴포넌트까지 위의 상황을 만족한다는 이유로 리렌더링이 되다 보면, 성능이 심하게 저하 되는 경우가 발생 된다. 이럴 때는 컴포넌트 리렌더링 성능을 최적화해 주는 작업을 해 주어야 한다.

즉, 리렌더링이 불필요할 때에는 리렌더링을 방지해 주어야 한다.

 

React.memo를 사용하여 컴포넌트 성능 최적화

컴포넌트의 리렌더링을 방지할 때는 shouldComponentUpdate라는 라이프사이클을 사용하면 된다.

그렇지만 함수 컴포넌트에는 라이프사이클 메서드를 사용할 수 없으므로 대신 React.memo 라는 함수를 사용한다.

 

React.memo 함수를 통해 컴포넌트의 props가 바뀌지 않았다면, 리렌더링 하지 않도록 설정할 수 있다.

 

사용법은 컴포넌트를 만들고 나서 export문에서 컴포넌트를 React.memo로 감싸주면 된다.

 

export default React.memo(TodoListItem);

 

 


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

  const onToggle = useCallback(
    (id) => {
      setTodos(
        todos.map((todo) =>
          todo.id === id ? { ...todo, checked: !todo.checked } : todo,
        ),
      );
    },
    [todos],
  );

 

위의 함수 onRemove와 onToggle은 가장 상단의 부모 컴포넌트의 state인 todos 배열이 업데이트가 될 때마다 함수가 새로 만들어진다.


 이렇게 함수가 계속 만들어지는 상황을 방지하는 방법은 두 가지이다.
첫 번째 방법은, 함수형 업데이트 기능을 사용하는 것
두 번째 방법은 useReducer을 사용하는 것이다.

 


useState의 함수형 업데이트

const [todos, setTodos] = useState([ {....} ,{....},{....} ]);

위와 같이 useState를 이용해 생성된 state를 변경할 때(setTodos), 

새로운 상태를 파라미터로 넣는 대신 상태 업데이트를 어떻게 할지 정의하는 업데이트 함수를 넣는 방법이다.

이를 함수형 업데이트라고 한다.

 

다음은 예시이다.

 

const [number,setNumber] = useState(0);
const onIncrease = useCallback( ()=> {
 setNumber(prevNumber => prevNumber+1),
 [],
);

 

단순히 setNumber(number+1)가 아닌 위의 코드처럼 작성하면 useCallback을 사용할 때 두 번째 파라미터로 넣는 배열에 number를 넣지 않아도 된다.

따라서 number가 변하는 매 순간마다 onIncrease 함수가 불필요하게 재생성되지 않으므로 성능 저하를 막을 수 있다.

 

userReducer 사용

useReducer를 사용하는 방법은 기존 코드를 많이 고쳐야 한다는 단점이 있지만, 상태를 업데이트 하는 로직을 모아서 컴포넌트 바깥에 둘 수 있다는 장점이 있다. 성능상으로는 두 방법이 비슷하기 때문에 어떤 방법을 선택할지는 각자의 취향에 따라 결정하면 된다.

 

 

나는 아직 Reducer의 개념을 공부하지 않아 useReducer를 사용하는 방법은 리덕스를 공부하고 난 뒤 다시 알아볼 생각이다.