[TIL] 250513_React: TanStack Query

지코·어제
0

Today I Learned

목록 보기
66/66
post-thumbnail

📌 TanStack Query에 대하여

TanStack Query서버 상태 관리의 복잡성을 극복하기 위해 사용하는 라이브러리이다. 여기서 서버 상태란 서버에서 제공하는 데이터로, 클라이언트에서 직접 수정할 수 없고 네트워크 요청과 같은 비동기 작업을 통해 가져오거나 갱신해야 하는 데이터를 의미한다.

React Query 라는 이름으로 시작했지만, v4부터 Vue나 Svelte 등의 다른 프레임워크에서도 활용할 수 있도록 기능이 확장되며, TanStack Query라는 이름으로 변경되었다.

이번에는 간단하게 주요 기능들과 사용 예시들을 살펴보고, 다음 번에는 실제 프로젝트에 적용하며 포스팅해보면 좋을 것 같다!

TanStack Query를 사용하는 주요 이유

1️⃣ 효율적인 캐싱 처리 기능 제공
이를 통해 동일한 데이터를 반복적으로 요청하지 않아 네트워크 비용을 절감하고, 캐싱된 데이터를 즉시 제공해 더 나은 사용자 경험을 제공할 수 있다.

2️⃣ 비동기 데이터 관리의 복잡성 감소
TanStack Query는 데이터의 가져오기(fetch), 갱신(refetch), 무효화(invalidate) 등의 작업을 선언적으로 처리할 수 있어, 코드가 간결해지고 유지보수가 용이해진다.

3️⃣ 에러 및 로딩 상태 관리 단순화
useQuery()useMutation() 훅을 사용하면, 서버 데이터와 관련된 로딩, 성공, 실패 상태를 명확하고 직관적으로 처리할 수 있어 로직이 깔끔해진다.

이외에도 무한 스크롤, 페이지네이션 등의 성능 최적화, 신선한 데이터 유지 등의 기능이 있다.

➡️ TanStack Query를 사용함으로써 서버 상태 관리에서 발생하는 복잡한 문제를 해결하고, 개발자가 비즈니스 로직에 더 집중할 수 있도록 도울 수 있다.

🤔 TanStack Query를 사용할 때 발생할 수 있는 단점이나 한계는 무엇일까?

1️⃣ 캐싱 전략 관리의 복잡성
TanStack Query는 강력한 캐싱 기능을 제공하지만, staleTime , gcTime 같은 옵션을 잘못 설정하면 데이터 갱신 타이밍이 적절하지 않아 최신 데이터가 사용자에게 노출되지 않거나 불필요한 요청이 발생할 수 있다.

2️⃣ 러닝 커브
Query Key 설계, 데이터 무효화 등 다양한 개념을 이해하고 적절히 활용해야 하므로 초기에 학습해야 하는 지식의 양이 많다.

3️⃣ 복잡성을 완전히 해결하지는 못함
클라이언트 상태와 서버 상태 간 의존 관계가 복잡한 경우, TanStack Query만으로는 해결하기 어려울 수 있다. 이때는 Redux, Zustand 등 별도의 상태 관리 라이브러리가 필요할 수 있다.


📌 TanStack Query를 사용해서 데이터 캐싱하기

TanStack Query를 활용해 데이터를 가져올 때는 항상 쿼리 키(queryKey)를 저장하게 된다. 이 쿼리 키는 캐시된 데이터와 비교해 새로운 데이터를 가져올지, 캐시된 데이터를 사용할지 결정하는 기준이 된다.

import { useQuery } from '@tanstack/react-query'

export default function DelayedData() {
	const { data } = useQuery({
      	// queryKey: 캐시를 식별하는 이름
		queryKey: ['delay'], 
		// queryFn: 실제 데이터를 가져오는 함수 (GET)
		queryFn: async () => (await fetch('https://api.heropy.dev/v0/delay?t=1000')).json()
	})
	return <div>{JSON.stringify(data)}</div>
}

쿼리 키(queryKey)는 배열 형태로 지정하며, 다중 아이템 쿼리 키를 사용할 때는 아이템의 순서가 중요하다.

// 단일 아이템 쿼리 키
useQuery({ queryKey: ['hello'] })

// 다중 아이템 쿼리 키
useQuery({ queryKey: ['hello', 'world', 123, { a: 1, b: 2 }] })

// 서로 같은 쿼리
useQuery({ queryKey: ['hello', 'world', 123, { a: 1, b: 2 }] })
useQuery({ queryKey: ['hello', 'world', 123, { b: 2, c: undefined, a: 1 }] })

// 서로 다른 쿼리
useQuery({ queryKey: ['hello', 'world', 123, { a: 1, b: 2 }] })
useQuery({ queryKey: ['hello', 'world', 123, { a: 1, b: 2, c: 3 }] })
useQuery({ queryKey: ['hello', 'world'] })
useQuery({ queryKey: [123, 'world', { a: 1, b: 2, c: 3 }, 'hello'] })

JSON.stringify는 기본적으로 객체의 속성을 삽입된 순서대로 직렬화한다. undefined 값은 무시되며, 순서가 동일하게 정렬되어 있으면 결과도 같을 수 있다.
반대로 속성이 추가되거나 배열 순서가 바뀌면 다른 쿼리로 처리된다.

쿼리 키(queryKey)와 일치하는 캐시된 데이터가 없을 경우에는 다음과 같이 서버에서 새로운 데이터를 가져오고, 서버에서 데이터를 가져오면 그 데이터는 캐시되며 그 이후 요청부터는 캐시된 데이터를 사용할 수 있다.

반대로 쿼리 키 와 일치하는 캐시된 데이터가 있으면, 서버에 요청하지 않고 캐시된 데이터를 사용한다. 그래서 같은 데이터에 대한 요청이 여러 번 발생하더라도 캐시된 데이터를 사용하게 되어 중복 요청을 줄일 수 있다.


📌 데이터의 신선도는 어떻게 확인할 수 있을까?

TanStack Query는 캐시한 데이터를 Fresh or Stale 상태로 구분해 관리한다. 캐시된 데이터가 신선한다면 캐시된 데이터를 사용하고, 캐시된 데이터가 상했다면 서버에 데이터를 재요청해서 새로운 데이터를 가져온다.

데이터가 상하는 데까지 걸리는 시간은 staleTime 옵션으로 지정할 수 있다. 그리고 상태 값은 isStale 로 확인할 수 있다.

import { useQuery } from '@tanstack/react-query'

export default function DelayedData() {
  const { data, isStale } = useQuery({
    queryKey: ['delay'],
    queryFn: async () => (await fetch('https://api.heropy.dev/v0/delay?t=1000')).json(),
    staleTime: 1000 * 10 // 10초 동안만 신선함. (ms 단위)
  })
  return (
    <>
      <div>데이터가 {isStale ? '상했어요.' : '신선해요!'}</div>
      <div>{JSON.stringify(data)}</div>
    </>
  )
}

Reference

📄 매일메일 - TanStack Query를 사용하는 이유를 설명해 주세요.
✍🏻 TanStack Query (React Query) 핵심 정리

profile
꾸준하고 성실하게, FE 개발자 역량을 키워보자 !

0개의 댓글