리액트쿼리(React-Query) 개념
공식문서 설명
TanStack Query(FKA React Query)는 종종 웹 애플리케이션용 누락된 데이터 가져오기 라이브러리로 설명되지만 좀 더 기술적인 용어로 말하면 웹 애플리케이션에서 서버 상태 가져오기, 캐싱, 동기화 및 업데이트를 매우 쉽게 만듭니다.
이런 느낌이다. 여기서 데이터는 상태(state)와 같다
결국 리액트쿼리를 사용하면 다음과 같은 효과를 볼 수 있다.
1. 서버와 통신하여 데이터를 가져올 수 있다.
2. 데이터를 캐싱하여 불필요한 서버통신을 줄일 수 있다.
3. 오래 된 데이터(stale)을 최신 데이터로(fresh) 업데이트 할 수 있다.
어떤 경우에 리액트 쿼리를 사용할까?
내 생각에는 다음과 같은 경우에 리액트 쿼리를 사용하면 좋을 거 같다...
1. 컴포넌트를 많이 쓰는 경우(서버에서 자주 데이터를 가져오는 경우)
컴포넌트 안에 비동기 통신을 하는 로직이 있다고 가정해보자.
10개의 컴포넌트를 import하여 사용한다면 해당 화면으로 이동했을 때, 10번의 네트워크 통신이 일어난다.
이때, 리액트 쿼리를 통해 캐싱된 데이터를 재사용한다면, 네트워크 통신은 최초 한번만 일어나고
그 이후로는 캐싱된 데이터를 사용하게 되어, 네트워크 통신 부담을 줄일 수 있다.
2. 변경이 자주 일어나지 않는 데이터를 가져오는 경우
1번과 비슷한 맥락인데, 변경이 자주 일어나지 않는 데이터의 경우에는 캐싱을 해놓고
가져다 쓰면 굳이 불필요한 네트워크 통신을 하지 않아도 되, 성능에 도움을 줄 수 있다.
실제 내가 했던 프로젝트를 예로 들면, 읍면동 데이터를 API를 통해 가져오는데, 읍면동 같은 경우에는
짧게는 1년 길게는 몇년 정도 데이터가 변경되지 않는다. (아마?)
그래서 이런 데이터를 리액트 쿼리로 작성하여 서비스 이용시에, 캐싱된 데이터를 사용하면
굳이 불필요한 네트워크 통신을 안해도 되지 않을까? 라는 생각을 했다.
3. 복잡한 캐싱 전략이 필요한 경우
리액트 쿼리에서는 캐싱에 대한 옵션만 파라메터로 넘기면 자동으로 캐싱된 데이터를 사용할 수 있고
상태(state)의 값이 변경되면 자동으로 리패칭(업데이트)를 해준다.
순수 javascript를 통해 캐싱 로직을 짜는 것 보다 리액트 쿼리를 사용하면 손 쉽게 캐싱 된 데이터라면
네트워크 통신을 하지 않도록 할 수 있다.
나도 몰랐는데, 이전 프로젝트에서 캐싱 관련 로직을 짰더란다. 만약 리액트 쿼리를 알았다면 썼을텐데
이외에도 다양한 경우에 사용할 수 있겠지만, 당장 생각나는 건 위의 3가지 경우이다..
리액트쿼리(React-Query) 기본 사용법
리액트 쿼리 설치
npm설치으로 설치하는경우
npm i @tanstack/react-query
--or
pnpm add @tanstack/react-query
--or
yarn add @tanstack/react-query
CDN으로 가져오는 경우
<script src="https://unpkg.com/@tanstack/react-query@4/build/umd/index.production.js"></script>
샘플코드
import {
useQuery,
useMutation,
useQueryClient,
QueryClient,
QueryClientProvider,
} from '@tanstack/react-query'
import { getTodos, postTodo } from '../my-api'
// Create a client
const queryClient = new QueryClient()
function App() {
return (
// Provide the client to your App
<QueryClientProvider client={queryClient}>
<Todos />
</QueryClientProvider>
)
}
function Todos() {
// Access the client
const queryClient = useQueryClient()
// Queries
const query = useQuery({ queryKey: ['todos'], queryFn: getTodos })
// Mutations
const mutation = useMutation({
mutationFn: postTodo,
onSuccess: () => {
// Invalidate and refetch
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
})
return (
<div>
<ul>{query.data?.map((todo) => <li key={todo.id}>{todo.title}</li>)}</ul>
<button
onClick={() => {
mutation.mutate({
id: Date.now(),
title: 'Do Laundry',
})
}}
>
Add Todo
</button>
</div>
)
}
render(<App />, document.getElementById('root'))
위 코드는 그냥 리액트쿼리 공식문서에서 가져온 샘플코드이다.
위 코드로 사용방법을 크게 나누어 보면 다음과 같다.
1. 리액트쿼리를 사용하고자 하는 컴포넌트에 QueryClientProvider contextAPI로 감싼다.
2. queryClient 생성자를 client props로 넘겨준다.
3. useQueryClient로 queryClient를 생성한다.
4. useQuery를 사용하여 data를 호출한다.
5. useMutation으로 데이터를 insert, update, delete 한다.
리액트쿼리 사용시 주의점
리액트쿼리를 사용한다면 보통 손쉬운 캐싱 설정을 통해 무분별한 네트워크 방지하고자 할텐데(나는 그렇다)
리액트 쿼리는 다음과 같은 경우에 데이터를 리패치(데이터 새로 불러옴) 하는데
1.새로운 쿼리가 만들어졌을 때(쿼리 키에 전달되는 state가 변경되어 리렌더링 일어났을 때)
2.윈도우가 다시 포커스되었을 때
3.네트워크가 다시 연결되었을 때
4.리페치 인터벌이 설정되었을 때
문제는 리패치 설정을 안하면 default가 stale인 데이터, 즉 오래된 데이터이기 때문에
무조건 네트워크 통신을 하게 된다.
refetchOnWindowFocus, //default: true
refetchOnMount, //default: true
refetchOnReconnect, //default: true
staleTime, //default: 0
cacheTime, //default: 5분 (60 * 5 * 1000)
staleTime
- staleTime은 데이터가 fresh → stale 상태로 변경되는 데 걸리는 시간이다.
- fresh 상태일 때는 Refetch 트리거(위의 3가지 경우)가 발생해도 Refetch가 일어나지 않는다!
- 기본값이 0이므로 따로 설정해주지 않는다면 Refetch 트리거가 발생했을 때 무조건 Refetch가 발생한다!
cacheTime
- cacheTime은 데이터가 inactive한 상태일 때 캐싱된 상태로 남아있는 시간이다.
- 특정 컴포넌트가 unmount(페이지 전환 등으로 화면에서 사라질 때) 되면 사용된 데이터는 inactive상태로 바뀌고, 이때 데이터는 cacheTime만큼 유지된다.
- cacheTime 이후 데이터는 가비지 콜렉터로 수집되어 메모리에서 해제된다.
- 만일 cacheTime이 지나지 않았는데 해당 데이터를 사용하는 컴포넌트가 다시 mount되면, 새로운 데이터를 fetch해오는 동안 캐싱된 데이터를 보여준다.
- 즉, 캐싱된 데이터를 계속 보여주는게 아니라 fetch하는 동안 임시로 보여준다는 것이다!
이외에도 사용자가 특정 이벤트가 발생했을 때 Refetching을 하도록 설정해줄 수 있다. React-Query의 이러한
기능들을 통해 사용자는 언제나 최선의 데이터를 제공받게 된다.
참조링크
https://zzang9iu.tistory.com/117