useMemo를 사용해 렌더링에 따라 불필요한 함수가 재호출 되지 않도록 했고,
useCallback을 사용해 렌더링에 따라 불빌요하게 함수가 재정의되지 않도록 했다.
이번에는 불필요한 렌더링을 막아보자.
React.memo
//선언 방법1
const ListContainer = React.memo(({ element, active, onRemove, onEdited }) => {
...
}
//선언 방법2
export default React.memo(ListContainer);
컴포넌트를 React.memo()로 감싸는 것만으로도 불필요한 렌더링을 막을 수 있다.
부모 컴포넌트에서 setState가 발생하면 자식 컴포넌트들이 모두 렌더링 되는데, 이때 props가 변경되지 않았다면 렌더링 하지 않는다.
이를 위해서 부모 컴포넌트에서 전송하는 함수를 모두 useCallback으로 만들어, 부모 컴포넌트가 setState 되더라도 부모의 함수들이 가리키는 메모리 주소가 변경되지 않도록 하였다. useCallback을 함께 사용하지 않는다면 함수를 전달해주는 경우 React.memo()가 의도한 대로 동작하지 않을 것이다.
useCallback 최적화하기
const onRemove = useCallback(
(id) => {
setResult(userList.filter((e) => e.id !== id));
},
[userList]
);
const onEdited = useCallback(
(editedElement) => {
setResult(
userList.map((e) => (e.id === editedElement.id ? editedElement : e))
);
},
[userList]
);
해당 함수들 처럼 배열이나 객체를 deps로 가지고 useState를 사용하는 useCallback 함수는 배열/객채의 일부가 변경되면 재배치된다.
따라서 이 함수들이 하위 컴포넌트의 매개변수로 넘겨지는 경우라면 변경된 배열/객체 요소와 다른 요소를 받는 모든 하위 컴포넌트들이 리 렌더링 된다. 실제 값은 변경된 것이 없음에도 말이다.
수정된 요소를 받는 컴포넌트만 리렌더링 되게끔 하려면 useCallback에서 useState와 관련되어 있는 배열/객체를 제거해주어야 한다.
const active = useCallback((id) => {
setResult((userList) =>
userList.map((e) => (e.id === id ? { ...e, isActive: !e.isActive } : e))
);
}, []);
const onEdited = useCallback((editedElement) => {
setResult((userList) =>
userList.map((e) => (e.id === editedElement.id ? editedElement : e))
);
}, []);
이처럼 useState를 함수형 업데이트로 선언하면 된다.
본래 방법에서는 useCallback이 deps를 통해 인자로 받은 값을 수정하는 방식이었다.
useState를 함수형 업데이트로 선언하면 useState에서 직접 state 값을 받은 후 그를 기반으로 업데이트를 진행한다.
또한, 함수가 큐에 담겨 순차적으로 동작하므로 동기적으로 동작하게 된다.
최적화에 관해
React.memo는 렌더링마다 props를 비교해 같다면 렌더링을 막는 방식이다.
제대로 사용하지 않으면 props를 비교하는 연산이 불필요하게 발생하므로, 최적화를 확실히 이룰 수 있을 때 사용해야 한다.
또한 arrow 함수는 함수를 새롭게 생성하기에 남발하면 성능에 문제가 발생한다.
'React > React Basic' 카테고리의 다른 글
[React] useContext 및 Context API (0) | 2021.08.08 |
---|---|
[리액트] useReducer 이해하기 (0) | 2021.08.07 |
[React] useMemo와 useCallback (0) | 2021.08.01 |
[React] mount시 실행되는 useEffect (0) | 2021.08.01 |
[React] List를 컴포넌트로 렌더링 (0) | 2021.07.31 |