React 프로젝트를 여러번 하면서 useCallback()
, useMemo()
등의 성능 최적화를 위한 hook을 사용해 본 경험이 없었다.
이번 프로젝트에서 한 번 제대로 사용해보자 결심했지만 시간에 쫓겨 도입하지 못했던 것이 불편했다. 이번 기회에 성능 최적화를 연습할 겸 제대로 리팩토링을 하고자 한다.
기존 네비게이션 로직 개선.Router 부분 코드 개선.useCallback()
,useMemo()
등의 React hook으로 성능 개선.- 웹 뷰에서 CSS 충돌 문제 해결.
useCallback()
, useMemo()
등의 React hook으로 성능 개선.이전과 동일하게 성능 최적화를 고려하지 않은 설계로 불필요한 리렌더링이 되는 컴포넌트들이 존재한다.
프로젝트 전반에 걸쳐서 성능 최적화가 필요한 상황이다.
해당 페이지에서는 총 3번의 렌더링이 발생한다.
1. Initial render.
2.useEffect()
에 작성된dispatch
(가게 목록 요청) 함수에 의해 redux의 가게 목록이 업데이트 되었고 이 가게 목록을 구독하는useSelector()
에 의해 render.
3. React.StrictMode에 의해 render. (개발 모드에서 확인)위의 이미지를 보면 3번의 렌더링 시, 모든 컴포넌트들이 리렌더링이 된 것을 확인할 수 있다.
기존 개선 방법
React.memo()
를 사용하여 하위 컴포넌트들이 리렌더링 되지 않도록 한다.useCallback()
을 사용하여 리렌더링이 발생하더라도 함수를 새로 만들지 않도록 한다.- 함수형 업데이트를 사용하도록
setState
로직을 개선하여useCallback
의 의존성 배열을 줄인다.
가게 홈 페이지 컴포넌트로부터 props로
storeList(가게 목록)
을 전달 받는 하위OrderStoreList(가게 목록 컴포넌트)
가 매번 리렌더링이 발생했다.이에 대한 원인은
React.memo()
가 이전 props들과 값을 비교할 때, 이전에 저장하고 있던storeList
와 새로 리렌더링 되면서 업데이트 된storeList
객체가 같지 않다고 판단했기 때문이었다.
해결 방법
React.memo()
의 두 번째 인자로 이전에 저장하고 있던storeList
와 새로 전달받은storeList
를 비교하는isSame()
콜백 함수를 구현하여 전달했다.
isSame()
을 추가한 후의 코드
React.memo()
와useCallback()
을 이용하여 이 페이지에서 사용하는 모든 하위 컴포넌트들을 재상용 할 수 있었고 리렌더링 비용을 크게 줄일 수 있었다.
이 리팩토링 기록 외에도 프로젝트 전체에 걸쳐서 최적화를 위한 리팩토링을 진행했다. 이번 리팩토링을 통해 그동안 능숙하다고 생각했던 React에 대해 공부가 부족했다는 것을 느꼈다. 하지만 useCallback()
과 같은 hook들과 useSelector()
를 이용한 성능 최적화 방법을 연습해 볼 수 있었으며 개발 중 아쉬웠던 부분을 다소 해결했기에 만족스럽다.
다음 프로젝트부터는 이번에 공부한 성능 최적화 방식을 적극적으로 도입할 수 있을 것 같다.