아하❓ (4) - useMemo 제대로 사용하기

김태완·2025년 2월 25일
post-thumbnail

GlobalNomad 프로젝트 진행 중 eslint가 날 위해 경고 메세지를 띄워줬다.

아래와 같은 경고 메세지였다!

→ 'myActivities'의 논리적 표현이 useEffect의 의존성 배열을 렌더링마다 변경할 수 있습니다. 이것을 고치기 위해서는 myActivities를 useMemo 훅으로 감싸세요?!

코드를 돌아보자.
최초에는 다음과 같이 구성했었다.

그런데 위와 같이 구성했을때는 렌더링시에 selectedActivity가 undefined값이 나왔다. 당연히 최초 렌더링 시점에는 useQuery가 데이터를 비동기적으로 가져오니 data가 undefinted이기 때문에 selectedActivity 빈배열에서 가져올게 없었겠지...

그래서 아래와 같이 useEffect로 렌더링 될때 초기값을 세팅해보려했다. data도 undefined일때는 빈배열을 내놓도록 수정했다.

경고 메세지에 따르면,
useEffect에서 myActivities를 의존성 배열로 사용했기 때문에 렌더링될 때마다 새로운 배열이 생성되므로, useEffect가 불필요하게 실행된다.... 고 이해했다...😨😨

useMemo를 써라?!
그럼 일단 useMemo 알아보자.

useMemo(calculateValue, dependencies)

  • 매개변수

    • calculateValue: 캐싱하려는 값을 계산하는 함수이다. 인자를 받지 않고, 모든 타입의 값을 반환할 수 있어야한다.
      -> React는 초기 렌더링 중에 함수를 호출한다. 다음 렌더링에서, React는 마지막 렌더링 이후 dependencies가 변경되지 않았을 때 동일한 값을 다시 반환한다. 그렇지 않다면 calculateValue를 호출하고 결과를 반환하며, 나중에 재사용할 수 있도록 저장한다.
    • dependencies: calculateValue 코드 내에서 참조된 모든 변할 수 있는 값들의 목록이다. props, state와 컴포넌트 바디에 직접 선언된 모든 변수와 함수가 포함된다. 의존성 목록은 일정한 수의 항목을 가져야 하며, [dep1, dep2, dep3]와 같이 인라인 형태로 작성돼야 한다. React는 Object.is 비교를 통해 각 의존성 들을 이전 값과 비교한다.
  • 반환값

    • 초기 렌더링에서 useMemo는 인자 없이 calculateValue를 호출한 결과를 반환한다.
    • 다음 렌더링에서, 마지막 렌더링에서 저장된 값을 반환하거나(종속성이 변경되지 않은 경우), calculateValue를 다시 호출하고 반환된 값을 저장한다.

오 이해가 대충 되는 것 같다. 아래와 같은 내용으로 확실하게 마무리하자!

() => 와 같이 인수를 받지 않고 계산하려는 값을 반환하는 계산 함수 이다.
계산 내부에서 사용되는 컴포넌트 내의 모든 값을 포함하는 종속성 목록 이다.

초기 렌더링에서 useMemo에서 얻을 수 있는 값은 계산 함수를 호출한 결과값 이다.

이후 모든 렌더링에서 React는 종속성 목록을 마지막 렌더링 중에 전달한 종속성 목록과 비교한다.
만일 (Object.is와 비교했을 때) 종속성이 변경되지 않았다면, useMemo는 이전에 이미 계산해둔 값을 반환한다. 그렇지 않다면 React는 계산을 다시 실행하고 새로운 값을 반환한다.

즉, useMemo는 종속성이 변경되기 전까지 재렌더링 사이의 계산 결과를 캐싱한다.

그렇다면
내가 작성한 코드에서 myActivities가 useEffect에 종속성 배열로 들어가 있었기 때문에 data가 변경되는 것과는 별개로 계속 새로운 배열을 생성해냈을 것이다..!
(맞지? 리액트야?)

하여튼 useMemo를 다음과 같이 적용해보았다.

결과적으로는
1. useMemo를 사용해 myActivities가 불필요하게 매번 새로 생성되지 않도록 막았다.
2. useEffect는 myActivities가 바뀔 때만 실행되므로 selectedActivity를 안정적으로 초기화할 수 있었다.

profile
중고

0개의 댓글