필자는 개인 프로젝트에서 최적화를 수행하면서 컴포넌트에 console.log나 console.count를 작성하여 컴포넌트의 리렌더링 횟수를 확인하였다.
그러다 React Developer Tools의 Profiler 기능이 생긴 이후에 컴포넌트 리렌더링 측정이 매우 편리해지고 리렌더링이 발생한 컴포넌트 타겟을 쉽게 알 수 있어서 자주 사용하고 있다.
그래서 이번 프로젝트에서도 React Dev Tools를 활용하여 컴포넌트 렌더링 성능을 개선해 보았다.
필자가 수행한 프로젝트는 온라인 북 커머스 플랫폼이다.
먼저, React DevTools를 브라우저에 설치해야 합니다. Chrome과 Firefox에서 확장 프로그램으로 제공된다. 다운로드
설치가 완료되면 브라우저 개발자 도구에 "Components", "Profiler" 탭이 추가된다.
리렌더링이 자주 발생하는 곳 찾기
성능을 개선하기 위해서 먼저 가장 리렌더링이 많이, 자주 발생하는 컴포넌트를 찾아야 한다.
생각이 먼저 떠오른 컴포넌트는 리스트 형식으로 여러 목록을 렌더링하는 조회 페이지가 떠올랐다. 해당 페이지는 북 데이터를 무한 스크롤로 구현하였다.
스크롤을 내리면 카테고리와 관련된 책 데이터를 API 요청을 통해 페이지네이션된 데이터를 클라이언트로 데이터를 받아와 컴포넌트로 렌더링 된다.
성능 개선 전
위 이미지에 대해 간략히 설명하자면 이렇다.
- BooksScroll 페이지에 대한 렌더링 지표이다.
- 부모 컴포넌트는 ul element, 자식 컴포넌트는 Book 컴포넌트이다.
- 렌더링된 페이지에서 동일한 자식 컴포넌트(Book)가 리렌더링된다.
- 만일 자식 요소가 100, 1000 이상으로 많아질 경우 불필요한 리소스 비용이 발생하게 된다.
목표는 바로 자식 컴포넌트의 불필요한 리렌더링을 방지하는 것이 목표다.
개선 방법
React.memo 활용
컴포넌트의 리렌더링을 방지하는 방법 중 메모이제이션 기법을 활용한 memo
를 컴포넌트에 적용하는 방법이 있다.
자식 컴포넌트에 memo
메서드를 적용하여 해당 컴포넌트를 메모이제이션 한다.
메모이제이션된 컴포넌트는 다음 렌더링 과정에서 가상 컴포넌트가 DOM 객체와 비교하는 과정을 거치면서 렌더링 대상에서 제외시킨다.
export const Book = React.memo(({ item, category }: BookProps) => {
return (
<React.Fragment>
<S.Item >
...more code line
</S.Item>
<Divider variant="fullWidth" />
</React.Fragment>
)
})
필자는 named export를 사용하였기 때문에 위와 같이 적용하였다.
memo
사용 시 주의할 점으로 메모이제이션 적용된 컴포넌트의 props에 참조 객체나 함수가 있는지 확인해야 한다. 만일 useCallback
이나 useMemo
가 적용되지 않은 참조 객체나 함수를 props로 받을 경우 컴포넌트에 memo
를 적용하여도 다시 리렌더링이 발생할 수 있다.
성능 개선 후
성능 개선 전과 비교하면 렌더링이 일어나지 않는 컴포넌트를 확인할 수 있다. 이렇게 아주 미세한 최적화 과정이지만 데이터가 방대한 경우에는 좋은 최적화 결과를 얻을 수 있을 것이라 생각한다.
Rendered at을 확인해 보면 모든 렌더링 마다 리렌더링이 발생하였던 이전과 달리 단 한번만 렌더링이 발생한 것을 확인할 수 있다.
현재 북(Book) 이미지도 같이 렌더링 하고 있는데, 이미지 최적화를 통한 LightHouse 렌더링 성능 측정을 통해 LightHouse 최적화 방법도 시도해 볼 예정이다.
Top comments (0)