느려지는 원인 분석
컴포넌트는 다음과 같은 상황에 리렌더링 된다.
- 자신이 전달받은 props가 변경될 때
- 자신의 state가 변경될 때
- 부모 컴포넌트가 리렌더링될 때
- forceUpdate 함수가 실행될 때
지금 상황을 분석해 보자. 먼저 할 일1을 체크 했을 때 App컴포넌트의 state가 변경되어 App 컴포넌트가 리렌더링 된다. 이어서 자식 컴포넌트인 TodoList 역시 리렌더링이 되고 TodoList의 자식 컴포넌트인 수많은 Todo 컴포넌트 역시 리렌더링 되며 성능의 저하가 발생된다. 할 일1은 리렌더링 되어야 하는 것이 맞지만 그 이외 값이 변경되지 않은 컴포넌트는 리렌더링할 필요가 없다.
React.memo를 사용하여 컴포넌트 성능 최적화
컴포넌트의 리렌더링을 방지하기 위해서 우리는 shouldComponentUpdate 라이프사이클을 사용했다. 라이프사이클 메서드를 사용할 수 없는 함수형 컴포넌트에서는 대신 React.Memo Hooks을 사용한다. React.memo를 사용해서 props이 바뀌지 않았다면 리렌더링하지 않도록 설정해 보겠다.
React.memo의 설정은 매우 간단하다. 컴포넌트를 만들고 나서 감싸 주기만 하면 된다. TodoItem 컴포넌트에 아래와 같이 React.memo를 적용해 보자.
export default React.memo(TodoItem);
onToggle, onRemove 함수가 바뀌지 않게 하기
현재 프로젝트에서 todos 배열이 업데이트되면 onRemove와 onToggle 함수도 새롭게 바뀌고 있다. 해당 함수는 배열 상태를 업데이트 하는 과정에서 항상 최신의 todods를 참조하기 때문이다. 이렇게 함수가 계속 만들어지는 상황을 방지하는 방법에는 두 가지가 있다. 첫 번째 방법은 useState의 함수형 업데이트 기능을 사용하는 것이도 두 번째 방법은 useReducer를 사용하는 것이다.
useState의 함수형 업데이트
기존에 세터함수를 사용할 때는 새로운 상태를 파라미터로 넣어 주었다. 이러한 방법 말고도 상태 업데이트를 어떻게 할지 정의해 주는 업데이트 함수를 넣을 수도 있다. 이를 함수형 업데이트라고 부른다. 아래 함수형 업데이트의 예시를 살펴보자.
const [number, setNumber] = useState('0');
//prevNumbers는 현재 number 값을 가리킨다.
const onIncrease = useCallback(
()=> setNumber(prevnumber => prevNumber +1),
[],
);
기존처럼 setNumber(number+1)을 하는 것이 아니라, 위 코드처럼 어떻게 업데이트할지 정의해 주는 업데이트 함수를 넣어준다. 그러면 useCallback의 두 번째 파라미터로 number를 전해줄 필요가 없어진다.
기존 코드의 setTodos 안에 todos=>만 넣어준다면 함수형 업데이트로 설정이 가능하다. 이제 useCallback의 파라미터로 todos를 전달할 필요가 없고 따라서 todos 상태가 변경되어도 함수는 바뀌지 않는다.
useReducer 사용하기
'Frontend > React' 카테고리의 다른 글
2021-05-21 :: useEffect (0) | 2021.05.25 |
---|---|
2021-05-20 :: Context API (0) | 2021.05.20 |
2021-05-07 :: 컴포넌트 성능 최적화1 (0) | 2021.05.11 |
2021-05-06 :: Todo Project1 (0) | 2021.05.06 |
2021-05-03 :: 리액트 라우터로 SPA 개발하기3 (0) | 2021.05.03 |