
위와 같은 페이지가 있다. page.tsx > List.tsx > Item.tsx \* n의 형태를 띄고 있다.
구조를 어떻게 짜야 렌더링을 최소화 할 수 있을까?
우선, 완료 버튼을 누르면 내가 누른 요소들의 상태를 서버에 전송해야 한다. 그렇기에 요소들의 상태를 선언은 버튼과 같은 depth에 있어야 한다. 버튼에는 setState, 각 Item에는 setState와 state를 넘겨주는 것이다.
그리고, 각 Item은 React.memo로 감싸야 한다. 왜냐하면, 한 요소의 상태가 바뀌면,그 부모 컴포넌트(List 컴포넌트)가 리렌더링이 일어나고, 그 자식들(Item 컴포넌트들) 또한 리렌더링이 일어나기 때문이다. 그런데 다른 Item은 바뀐 것이 없기 때문에 리렌더링이 일어날 필요가 없다. 즉, 불필요한 리렌더링이다.
또한, Item에 넘겨주는 함수도 신경써야 한다. setState 자체는 리렌더링이 일어나도 참조가 그대로 유지되지만, () => handler(id)처럼 렌더링할 때마다 새로 만드는 핸들러는 매번 다른 객체이기에 Item컴포넌트는 리렌더링이 일어난다. 이런 함수는 부모 컴포넌트에서 useCallback으로 감싸, 함수의 불변성을 지켜야 한다.

useCallback을 사용할 때 eslint의 react-hooks rule을 무시하는 방법을 사용했다. useCallback 공식문서에서는 useCallback을 컴포넌트의 최상단에서 선언하라고 쓰여있다. 그런데, PersonalityItem에 넘겨주는 props인 onClick함수를 넘길 때 handlePersonality함수의 인자로 id를 넘겨주어야한다. 이 id는 map함수에서 가져온 id값이여서 컴포넌트의 최상단에서 선언할 수가 없다. 최상단에서 선언된 handlePersonality함수를 useCallback을 통해 메모이제이션을 해도 props로 넘길 때 () => handlePersonality(id)로 무기명 함수로 또 선언되기에 메모이제이션한 것이 의미가 없어진다. id를 인자로 넘겨야 하는 이상 이 부분은 한계로 남는다.

각각 React.memo, useCallback으로 memoization을 하기 전과 후이다. 확연한 렌더링 차이가 있다. 작은 규모의 프로젝트에서는 크게 체감이 안될 수 있지만, 이러한 것들이 쌓이고 쌓이면 크나큰 성능차이를 불러일으킬 것이다.