제가 직접 겪고 몸소 겪은 후 나중에 같은 실수 안반복하려고 정리합니다...
React로 개발하다보면 react-query를 써야하는 경우가 있다
Q. @tanstack/react-query 왜 쓰나요?
안좋은 답변: 친구들이 쓰길래요 (x)
한줄요약
비동기 데이터(fetching, caching, 갱신 등)을 효율적으로 관리하고, 이로 인한 복잡도를 줄이기 위함
같은 데이터를 여러 곳에서 사용하는데 매번 api를 요청한다면... 필요없는 네트워크 트래픽이 늘어남
react query는 query key로 캐시된 값을 불러와서 사용하는 등의 작업이 가능함
캐싱이 편해서 GOAT임
예전에 연구실에서 개발할 때 몇 백개의 문제 데이터를 미리 가져와서 클라이언트가 들고 있어야 하는...
뭐 그런 개발 시나리오가 있었는데 그때 react-query가 힘내서 캐싱했다네요 (쿼리야 힘내!)
며칠 전에 매일메일에서 관련 질문이 왔어서 같이 정리해야겠다
[매일메일] Tanstack Query를 사용하는 이유를 설명해주세요 (FE.250212, 86번)
tanstack-query는 서버 상태 관리 복잡성을 극복하기 위해 사용하는 라이브러리
서버 상태는 서버에서 제공하는(보내주는) 데이터임(api 응답 데이터)
클라이언트에서 직접 수정할 수 없고 네트워크 요청같은 비동기 작업으로 가져오거나 갱신해야 함
장점
1. 효율적인 캐싱 처리 기능
동일한 데이터를 반복 요청하지 않아 네트워크 비용을 절감한
캐싱된 데이터를 바로 불러와서 더 나은 UX를 제공함(초기 방문 이후 로딩 속도 줄이기)
2. 비동기 데이터 관리의 복잡성 완화
데이터 가져오기(fetch), 갱신(refetch), 무효화(invalidate) 등의 작업을 선언적으로 처리할 수 있음
(선언적으로 처리하는 건 개발자가 처리 과정을 지정하는게 아니라 처리 작업 뭐할지만 명시하는 거)
코드가 간결해지고 유지보수가 용이해짐
3. 에러 및 로딩 상태 관리 단순화
useQuery(), useMutation() 훅으로 서버 데이터와 관련된 로딩, 성공, 실패 상태를 직관적으로 처리
4. 재시도(retry) 로직 제공
서버에 문제가 있어서 데이터를 못가져오면 자동으로 재시도하도록 설정할 수 있음
5. 낙관적 업데이트
useMutation 훅, 서버에 데이터 변경 요청을 보내기 전 클라이언트에서 ui 변경 사항 즉시 반영
(일단 화면에 반영하고, 서버에 보내는 방식)
(블로그 관련 글: 낙관적 업데이트란? https://developer-dreamer.tistory.com/131)
단점
1. 캐싱 전략 관리 복잡성
staleTime(유효 시간), gcTime(삭제 시간) 옵션을 잘못 설정하면 데이터 갱신을 제때 못할 수 있음
(staleTime/gcTime이 뭔지는 이 글 맨 하단에 더 자세히 나옴)
2. 초기 학습 곡선 존재
Query Key 설계, 데이터 무효화 등 다양한 개념을 이해하고 적절히 활용해야 해서 초기 학습 곡선 높음
3. 클라이언트 상태/서버 상태 사이 의존 관계가 복잡하면 tanstack-query만으로 해결이 어려움
전역 상태관리를 직접 설계해야 하는 redux, zustand가 필요할 수 있음
(redux는 전역 상태나 변수, 데이터를 직접 설계하는 근본 전역 상태 라이브러리인데 보일러플레이트 코드가 많아서 학습 곡선이 높은 편임. 그래서 tanstack-query는 이런 상태 관리를 비교적 쉽게 할 수 있어서 주로 사용하는 건데, 상태가 너무 복잡해서 개발자의 설계가 깊게 개입되어야 하면 redux로 아예 짜는 게 나을수도... 구관 is 명관)
Q. 그래서 v4 v5 차이가 뭔가요?
실전 압축 에러 처리를 위해 suspense와 error boundary를 야무지게 섞어먹던 중...
useQuery에서 suspense: true, useErrorboundary: true, retry: true를 시도했으나...
"응 이 옵션 react-query에 없어!"를 뱉어내는 react...
react-query v5에서 해당 옵션이 사라졌다
v5는 2023년 10월에 출시됐다고 한다 v4는 2022년 7월 출시....
? 1년에 버전을 뭔 하나씩 찍어내네...
무튼 Suspense와 Error boundary에서 사용법이 좀 달라져서 발견한 김에 정리해봄
1. Suspense
suspense가 뭔데여???
> 이 블로그의 다른 글: Suspense란? https://developer-dreamer.tistory.com/158
🌟[공부, 매일메일] Suspense란?
SuspenseReact의 Suspense는 비동기적인 데이터 로딩을 보다 자연스럽게 처리할 수 있도록 도와줌특정 컴포넌트가 데이터를 가져오는 동안 로딩 상태(Loading State)를 보여줌 핵심 개념1. 비동기 렌더링
developer-dreamer.tistory.com
데이터를 비동기적으로 가져오면, api 응답이 올 때까지 시간이 걸리는 경우가 있음
이때 화면이 걍 비어있으면 사용자는 '뭐지 왜 흰 화면만 뜨지? 버근가?'라고 생각하게 됨
이때 loading fallback ui를 먼저 그려서 사용자에게 '좀만 기달려~'라고 알려줄 수 있는게 Suspense
보통 페이지 들어가면 정보 뜨기 전에 회색 네모 색이 그라데이션으로 변하는 화면이 보이는데
loading 상태에서는 그런 skeleton(뼈대)를 보여주거나 아니면 무한 빙글뱅글이를 보여주거나..그건 개발자 마음이다
아무튼 그런 로딩 상태 ui가 있으면 사용자는 '음 좀 기다리면 되나보네'라고 생각하게 된다
@tanstack/react-query v4
react-query가 데이터를 불러오는 동안 suspense의 fallback ui를 보여주려면,
useQuery의 속성 중 suspense: true를 설정하면 된다
export const testQuery = () => {
return useQuery({
queryKey: [QueryKeys.testData],
queryFn: getTestData,
suspense: true,
});
};
@tanstack/react-query v5
v5에서는 useQuery의 suspense: boolean 옵션이 제거되었다
대신 useSuspenseQuery, useSuspenseInfiniteQuery, useSuspenseQuries를 제공한다
suspense가 아예 적용된 Query 훅을 제공하는 쪽으로 바꾼 것 같다
Tanstack query v5의 Suspense https://tanstack.com/query/v5/docs/framework/react/guides/suspense
export const testQuery = () => {
return useSuspenseQuery({
queryKey: [QueryKeys.testData],
queryFn: getTestData,
});
};
2. Error boundary
에러 바운더리가 몬가요!
이 블로그의 다른 글: Error Boundary란? https://developer-dreamer.tistory.com/159
[매일메일] Error Boundary란? (FE.250205)
Error BoundaryReact 컴포넌트에서 발생하는 오류를 잡아내고, 전체 어플리케이션이 먹통 것을 방지하기 위한 컴포넌트 Error Boundary는 클래스형 컴포넌트에서만 사용할 수 있음 (함수 컴포넌트로 작
developer-dreamer.tistory.com
React 컴포넌트에서 발생하는 오류를 잡아서 처리할 수 있는 컴포넌트
React는 기본적으로 비동기 작업에서 오류가 발생하면 따로 처리를 해주지 않음(걍 흰화면 띄우거나)
그래서 에러가 발생한 영역에서 error fallback ui를 표시할 수 있도록 도와주는 컴포넌트
suspense를 error boundary로 감싸서 같이 사용하는 경우도 있다
시나리오는 대충 이렇다
일단 화면에 들어감 -> 데이터 요청 보내고 기다리는 동안 Suspense가 fallback ui 띄움
-> 데이터 요청 보냈는데 fail 응답 옴 -> Error Boundary가 fallback ui 띄움
그래서 <ErrorBoundary><Suspense>{children}</Suspense><ErrorBoundary> 이렇게 세트로 묶어서
wrapper 컴포넌트를 만들어서 사용하는 경우도 봤음(나도 그렇게 씀)
이 error boundary를 사용하려면 useQuery에서 또 에러 던져주라고 말해줘야 한다
One thing that Error Boundaries cannot do is catch asynchronous errors, because those do not occur during rendering. So to make Error Boundaries work in React Query, the library internally catches the error for you and re-throws it in the next render cycle so that the Error Boundary can pick it up.
https://tkdodo.eu/blog/react-query-error-handling#error-boundaries
error boundary는 렌더링 중에 발생한 에러를 포착할 수 없고, react-query는 이 에러를 감지해서
다음 렌더링 주기에 error boundary가 처리할 수 있도록 던져주는 역할을 한다고 함
@tanstack/react-query v4
useErrorboundary 옵션을 true로 설정한다
export const testQuery = () => {
return useQuery({
queryKey: [QueryKeys.testData],
queryFn: getTestData,
suspense: true,
useErrorboundary: true,
});
};
@tanstack/react-query v5
throwOnError 옵션을 true로 설정해준다
const testQuery = () => {
useQuery({
queryKey: [QueryKeys.testData],
queryFn: getTestData,
throwOnError: true,
});
};
useSuspenseQuery, useQuery 둘 다 throwOnError 속성이 존재하는 것으로 보인다.
머 로딩 처리 안하고 에러 처리만 하고 싶을수도 있지 ㅇㅇ
그 외 V4 vs V5 차이점
그리고 v4에서는 useQuery(key, fn, options)랑 useQuery({queryKey, queryFn, ...options}) 둘 다 지원했는데
v5부터는 useQuery({queryKey, queryFn, ...options})인 object 형태만 지원하는 점이 가장 큰 차이점!
tanstack react-query v4와 v5 주요 차이점 공식 가이드
https://tanstack.com/query/latest/docs/framework/react/guides/migrating-to-v5
Migrating to TanStack Query v5 | TanStack Query React Docs
Breaking Changes v5 is a major version, so there are some breaking changes to be aware of: Supports a single signature, one object useQuery and friends used to have many overloads in TypeScript differ...
tanstack.com
v4-v5 차이점을 한글로 번역한 블로그!
https://velog.io/@autumnhee/React-Migrating-to-TanStack-QueryReact-v5-%EB%B3%80%EA%B2%BD
React | Migrating to TanStack Query(React) v5 변경
프로젝트에서 @tanstack/react-query를 v4 쓰고 있다가 이번에 v5로 변경하였다.제일 큰 변화점은 v5부터는 객체 형식만 지원한다는 점이다.참고 https://tanstack.com/query/v5/docs/react/reference/Quer
velog.io
gpt랑 claude는 시간이 2022년에 멈춰있는건지 react-query v4로만 주로 답변한다
나는 v5가 나온지 얼마 안된 라이브러리라 그런가 싶었는데 23년 10월이면 시간 지날대로 지난건데 db 업뎃 좀 해라
매일메일에서 tanstack 관련 질문을 보내줬어서 그것도 같이 정리해야겠다
[매일메일] tanstack-query에서 staleTime과 gcTime의 차이점이란? (FE.241217, 5번)
react-query는 데이터 캐싱 맛집이다
매번 데이터를 불러오지 않고 저장해뒀다가 꺼내먹으면 트래픽도 줄고 얼마나 좋은가!
하지만 맛있는 캐시도 오래 보관하면 상하기 마련이다... 그땐 새 데이터를 불러와야 한다
그거랑 관련있는게 staleTime이랑 gcTime이다
staleTime은 유통 기한이고, gcTime은 사용자 소비 기한같은 느낌 아닐까
staleTime
데이터를 신선한 상태로 간주하는 시간
같은 쿼리에 대해 새로운 네트워크 요청을 일으키지 않고, 캐시 데이터를 그대로 사용하게 됨
default 값은 0임
ex: staleTime을 5분으로 설정, 데이터를 가져오고 5분 동안은 데이터가 '신선하다'고 판단해 캐시 데이터 사용
gcTime
우선 이 gcTime 옵션은 v5 업데이트랑도 관련있다. v4까지는 cacheTime이었던 옵션임!
cacheTime이란 이름을 보면 대충 캐시 지속 시간 같다는 생각이 들지 않는가? 대충 그거 맞음
왜 gcTime으로 이름을 바꿨을까...?(ㄹㅇ 의문)
해당 쿼리가 더 이상 사용되지 않을 때, 캐시 데이터가 메모리에 얼마나 더 지속될지 정함
staleTime이 지나면 데이터는 '오래된' 상태가 되지만, 캐시에 남아있어서 사용할 수 있음
하지만, 이 쿼리가 사용하지 않게 된 시점으로부터 gcTime으로 설정된 시간이 지나면 캐시에서 삭제함
default 값은 5분임
ex: gcTime 10분으로 설정하면, 해당 쿼리를 사용하는 컴포넌트가 모두 언마운트 된 시점으로부터 10분 후 캐시에서 데이터 삭제 됨
staleTime이 지나면 데이터가 비신선 상태(Stale)로 변경됨
gcTime이 지나기 전까지 메모리에 남아 있음
gcTime이 지나면, 해당 데이터는 완전히 삭제(Garbage Collection)되어 다시 API 요청을 보냄
무튼 버전 확인 잘 하고 즐거운 코딩 하세요~~
2025.02.14.
'개발자 강화 > 프론트엔드' 카테고리의 다른 글
[개발][BFF 도전기] Next.js 구축, Fastify에 Swagger 안 붙는 문제 해결하기 (1) | 2025.02.16 |
---|---|
🌟[매일메일] 이벤트 전파(Event Propagation)란? (FE.250106) (0) | 2025.02.14 |
[매일메일] 민감한 데이터는 어디에 저장해야 할까? (FE.250211) (0) | 2025.02.11 |
[공부] BFF API란? (1) | 2025.02.10 |
🌟[공부, 매일메일] Suspense란? (1) | 2025.02.10 |