React 16.6의 React.memo와 성능 최적화
배경
관리자 대시보드의 테이블 컴포넌트에서 성능 문제가 있었다. 부모 컴포넌트의 state가 변경될 때마다 모든 행이 리렌더링되면서 스크롤이 버벅였다.
기존에는 클래스형 컴포넌트에서 PureComponent를 사용했는데, 최근 함수형 컴포넌트로 전환하면서 성능 최적화 방법이 필요했다.
React.memo 적용
React 16.6에서 추가된 React.memo를 적용했다. HOC 방식으로 컴포넌트를 감싸면 props를 shallow compare하여 변경이 없을 때 리렌더링을 스킵한다.
const TableRow = React.memo(({ id, name, status, onUpdate }) => {
return (
<tr>
<td>{id}</td>
<td>{name}</td>
<td>{status}</td>
<td>
<button onClick={() => onUpdate(id)}>수정</button>
</td>
</tr>
);
});
콜백 함수 문제
처음엔 제대로 동작하지 않았다. 부모 컴포넌트에서 인라인으로 전달한 onUpdate 함수가 매번 새로 생성되면서 props 비교가 실패했기 때문이다.
// 문제가 있던 코드
{rows.map(row => (
<TableRow
key={row.id}
{...row}
onUpdate={(id) => handleUpdate(id)} // 매번 새 함수 생성
/>
))}
함수를 컴포넌트 외부로 빼거나, 필요하다면 useCallback을 사용해야 한다는 걸 알게 됐다. 하지만 Hooks는 아직 정식 릴리즈 전이라 16.7 알파 버전에서만 사용 가능하다.
당장은 클래스 메서드로 정의해서 해결했다.
결과
500개 행 기준으로 스크롤 성능이 체감상 2~3배 개선됐다. Chrome DevTools의 React Profiler로 확인해보니 불필요한 렌더링이 90% 이상 줄었다.
함수형 컴포넌트에서도 성능 최적화가 가능해진 건 좋지만, 콜백 함수 처리는 여전히 신경 써야 할 부분이다. Hooks가 정식 릴리즈되면 useCallback으로 더 깔끔하게 처리할 수 있을 것 같다.