Tanstack Query에서 메모이제이션이 필요없는 상황

eeensu·2026년 3월 27일

개요

실무 코드 리뷰 시 가장 자주 지적하게 되는 '불필요한 메모이제이션(Over-memoization)' 상황들을 단계별로 명확히 알아보자.

TanStack Query는 라이브러리 내부적으로 이미 고도의 최적화가 되어 있기 때문에, 컴포넌트 단에서 습관적으로 useCallback이나 useMemo를 남발하면 오히려 메모리 할당 비용만 증가시키게 되는 상황이 있다.

메모이제이션이 전혀 필요 없는 4가지 핵심 상황을 정리해보자.

1. 쿼리 키(Query Key) 배열의 선언

초보자분들이 가장 많이 하는 실수 중 하나가 렌더링마다 배열이 새로 생성되는 것을 막겠다며 쿼리 키를 useMemo로 감싸는 것이다.

  • 잘못된 예: const queryKey = useMemo(() => ['user', id], [id]);
  • TanStack Query는 내부적으로 쿼리 키값의 배열을 메모리 참조 주소를 비교하는 것이 아니라, 배열 안에 들어있는 실제 값들을 문자열 형태로 직렬화하여 캐시 키로 사용한다.
  • 매 렌더링마다 ['user', id] 형태의 새로운 배열 객체가 생성되어도 프레임워크가 알아서 동일한 키로 인식하므로, 인라인 배열로 바로 작성해도 상관없다.

2. useMutation의 콜백 함수들 (onSuccess, onError 등)

  • 잘못된 예 : const handleSuccess = useCallback(() => { ... }, [deps]);
  • TanStack Query의 Observer가 컴포넌트 렌더링 시점마다 전달되는 최신 옵션 객체를 내부 인스턴스에 덮어씌운다. 비동기 작업이 끝나는 시점에는 항상 가장 마지막에 렌더링된 최신 상태의 콜백을 찾아 실행한다.
  • 결론 : 인라인 익명 함수로 onSuccess: () => { } 처럼 전달해도 오래된 클로저(Stale Closure) 문제가 발생하지 않으며, 참조가 깨져도 무방하다.

3. 반환되는 data 객체의 메모이제이션

API로부터 받아온 data를 자식 컴포넌트에 넘길 때, 참조를 유지하겠다며 useMemo를 씌우는 경우이다.

  • 잘못된 예 : const memoizedData = useMemo(() => data, [data]);
  • TanStack Query는 구조적 공유(Structural Sharing)라는 기능을 기본적으로 탑재하고 있다. 이전 데이터와 새로 페칭된 데이터를 깊은 비교(Deep Compare)하여, 실제 값이 변하지 않았다면 이전 데이터의 메모리 참조를 그대로 반환한다.
  • API 재요청이 일어나더라도 실제 데이터 내용이 똑같다면 data의 참조는 이미 라이브러리 단에서 완벽하게 유지되고 있다. 컴포넌트에서 또다시 useMemo를 걸 필요가 전혀 없다.

4. 반환되는 mutate, refetch, fetchNextPage 등의 메서드

훅에서 반환받은 실행 함수들을 자식 컴포넌트의 props나 useEffect의 의존성 배열에 주입 할때 발생하는 상황이다.

  • useQuery나 useMutation에서 반환하는 refetch, mutate, mutateAsync 등의 함수들은 내부적으로 Observer 인스턴스에 바인딩된 고정된 참조(Stable Reference)를 가진다.
  • 컴포넌트가 아무리 리렌더링되어도 이 함수들의 메모리 주소는 절대 변하지 않는다. 따라서 자식 컴포넌트(React.memo가 적용된)에 props로 바로 내려주어도 리렌더링을 유발하지 않으며, useCallback으로 감싸는 것은 100% 무의미한 코드가 된다.

예외 상황 (메모이제이션이 필요한 경우)

단 하나, 주의해야 할 예외가 있다. useQuery의 select 옵션을 사용할 때이다.
select 함수 내에서 filter나 map처럼 새로운 배열/객체를 반환하는 무거운 가공을 할 경우, 데이터가 변경될 때마다 새로운 참조가 생성된다. 이때는 비용이 큰 연산을 방지하기 위해 select 함수 자체를 useCallback으로 감싸는 것이 구조적 공유를 유지하고 성능을 최적화하는 데 도움이 될 수 있다. 이는 프로파일러로 직접 체크하며 확인하면 좋다.

profile
안녕하세요! 프론트엔드 개발자입니다! (2024/03 ~)

0개의 댓글