hmk run dev
리액트 성능 측정 & 개선하기 (feat. memo & React DevTools) 본문
리액트 성능 측정하기 - 효율적인 테이블 컴포넌트 구현
사내에서 테이블 컴포넌트를 만들어야 하는 일이 생겼습니다.
그러나 특정 조건들로 인해 성능이슈가 생겼는데요
1. 페이징 처리가 없는 테이블의 형태
2. 옵션값 개수의 모든 경우의 수를 고려한 옵션생성(수십 ~ 수백 개의 테이블 row UI가 생김)
3. 판매 마켓별로 옵션들의 값을 수정할 수 있는 UI
4. 테이블 데이터(옵션)들을 일괄변경 할 수 있는 기능(자주 사용할 것으로 판단)
페이징 처리가 없는 테이블과 자주 사용되는 데이터 일괄 변경 기능은 리액트에서 성능 문제를 초래할 수 있습니다.
특히 수백 개의 테이블 row가 재렌더링 되는 경우, 애플리케이션의 성능 저하가 발생할 수 있습니다.
성능 측정과 개선
성능 측정은 React DevTools의 Profiler를 이용했습니다.
메모 적용 전
총 렌더링 소요 시간 - 2.7s
테이블 렌더링 소요 시간 - 87.3ms
Table Row 메모 적용 후
총 렌더링 소요 시간 - 1.7s
테이블 렌더링 소요 시간 - 85.3ms
적용코드
export const TableItem = React.memo(Component);
Table Cell 메모 적용 후
성능측정 결과 가장 결과가 좋았습니다.
총 렌더링 소요 시간 - 1.4s
테이블 렌더링 소요 시간 - 27.6ms
아래의 UI를 보면 선택된 row와 선택된 row들의 데이터를 일괄 수정할 수 있는 버튼 UI가 보인다.
각 셀이 일괄 변경될 수 있는 경우가 다르다는 것을 알 수 있는데,
Row뿐만 아니라 각 Cell에도 메모제이션을 적용하면 일괄 변경 시 성능상 이점을 가져갈 수 있을 것으로
판단해 각 Cell에 memo를 적용했습니다.
적용코드
아래와 같이 각 Cell에 memo를 적용했습니다.
일반적으로 memo는 얕은 비교를 수행해 참조형 데이터를 props로 받는 cell의 경우엔 아래와 같이
- memo shallow eqaul 참고
deep compare를 수행하는 lodash의 isEqual을 사용해 memo의 두 번째 인자에서
props의 변화를 감지하는 방식으로 구현했습니다.
import { isEqual } from 'lodash';
export const FinalPriceCell = React.memo(Component, (prevProps, nextProps) => {
return isEqual(prevProps, nextProps);
});
결론
React.memo()는 리액트에서 메모이제이션의 장점을 얻게 해 주는 훌륭한 도구다.
올바르게 적용된다면 변경되지 않은 동일한 prop에 대해 리렌더링을 하는 것을 방지할 수 있습니다.
But,
- 무분별한 memo는 오히려 메모리 사용 증가로 성능상 저하를 유발할 수 있습니다.
- 원시형이 아닌 참조형 데이터를 props로 넘길 때 memo가 의도대로 동작하지 않을 수 있으므로, 깊은 비교가 필요합니다.
- 콜백 함수를 prop으로 사용하는 컴포넌트에서 메모이지을 할 때 주의가 필요합니다.
- 같은 렌더링을 할 때 이전과 동일한 콜백 함수 인스턴스를 넘기는지 확인이 필요합니다.
- 메모이제이션의 성능상 이점을 측정하기 위해 profiler를 사용해 보는 것이 좋습니다.
Reference
'React' 카테고리의 다른 글
useMemo와 useCallback (0) | 2022.03.22 |
---|---|
Next.js 정적 생성(Static Generation) - getStaticProps, getStaticPaths (0) | 2022.03.01 |
next.js의 SSR (0) | 2022.03.01 |
Next.js의 장점과 프로젝트 구조 (0) | 2022.03.01 |
async, await (0) | 2021.05.20 |