useMemo with comparator

김동하·2023년 3월 25일
2

react

목록 보기
30/31

들어가며

예제

위와 같은 검색 앱이 있다고 가정하자. List Item에 hover를 하면 highlight가 되면서 리렌더링이 일어난다.

List Item 컴포넌트는 여러 props를 받고 있고 그 중 index와 hover된 아이템의 index를 받아 style을 변경하고 있다.

문제 상황

위의 상황에서 List Item 한 개의 highlightedIndex 변경 시 전체 List Item 컴포넌트가 리렌더링 되는 문제가 발생한다.

0번 인덱스의 아이템의 highlightedIndex만 변경했다.

하지만 위에 보이는 것처럼 두 개의 커밋에 List Item 전체가 리렌더링 되었다. 이를 해결하기 위해 React.memo에 비교 함수를 추가해줘야 한다.

React.memo

React는 먼저 컴퍼넌트를 렌더링(rendering) 한 뒤, 이전 렌더된 결과와 비교하여 DOM 업데이트를 결정한다. 만약 렌더 결과가 이전과 다르다면, React는 DOM을 업데이트한다.
다음 렌더링 결과와 이전 결과의 비교는 빠르다. 하지만 어떤 상황에서는 이 과정의 속도를 좀 더 높일 수 있다.
컴퍼넌트가 React.memo()로 래핑 될 때, React는 컴퍼넌트를 렌더링하고 결과를 메모이징(Memoizing)한다. 그리고 다음 렌더링이 일어날 때 props가 같다면, React는 메모이징(Memoizing)된 내용을 재사용한다.

이렇게 React.memo의 두 번째 인자로 함수를 추가한다. return true일 때는 리렌더링을 하지 않는다. 반대로 false일 경우 리렌더링한다. 아래는 return true일 경우다.

이제 원하는 조건을 추가하여 리렌더링을 관리하자.

<ListItem> 컴포넌트가 받는 props를 이전 props와 비교하고 마지막으로 highlight 조건도 준다.

이렇게 리렌더링이 되지 않아도 되는 조건, 즉 prev에도 highlight 되었고 next에도 highlight 된 경우와 그 반대의 경우(prev, next 둘 다 highlight 가 아닌 경우) 이 두 경우에 리렌더링이 되지 않게 한다.

딱 원하는 경우만 리렌더링 되는 것을 확인할 수 있다!

즉, 위의 코드는 React.memo 를 사용했을 때 리액트가 기본적으로 props를 비교하는 계산이다. 하지만 비즈니스 로직에 따라 이런 비교로는 리렌더링을 못 막는 경우가 있다. highlightedIndex props의 경우 모든 prev가 -1이라서 모두 리렌더링이 된다.

그래서 위처럼 비즈니스 로직에 따라 리렌더링을 할지 안 할지 결정해주는 조건을 추가로 작성해줘야 한다.

further

저렇게 매번 코드를 작성하는 건 불편하다. 그래서 가장 쉬운 방법은 불변값을 미리 만들어서 비교하는 것이다.

해당 컴포넌트가 highlighted 되었는지 판단하는 boolean 값을 상위 컴포넌트로 올려서 props로 주는 것!

그리고 이렇게 boolean 값의 이전과 현재만 비교해주면 (React.memo의 기본 비교와 동일하게 코드 수정)

똑같이 불필요 리렌더링을 방지할 수 있다!

즉, DOM 업데이트를 판단하는 값은 상위에서 내려서 React.memo의 기본 비교로 수행할 수 있도록 하는 것이다.

참고 :

profile
프론트엔드 개발

1개의 댓글

comment-user-thumbnail
2024년 8월 9일

import { memo } from "React"
형태로 해서 사용하는 게 좋겠습니다.
React.memo 형태의 컨벤션은 잘 사용하지 않으려고 하는 추세인 것 같습니다.
아마 js로 컨버팅 이후에 컴포넌트가 조금 더 커지기도 할 것 같고요

답글 달기