
참고 : Client State와 Server State
Client State
- 웹 브라우저 세션과 관련된 데이터
- ex) 언어 선택, 테마 선택
Server State
- 서버에 저장된 데이터. 클라이언트에 표시하기 위해 필요
- ex) 블로그 게시물 데이터

Server State(서버 상태)를 관리하는 리액트 라이브러리
서버 데이터의 캐시를 관리 (해당 캐시의 데이터를 설정한 바에 따라 유지 관리)
서버 데이터가 필요할 때, fetch, axios 등을 이용해 바로 서버에 요청하지 않고, 일단 React Query cache를 요청한다.
서버의 새 데이터로 캐시를 업데이트하는 시기는 사용자가 지정해줘야 한다.
캐시 업데이트 시점을 지정해주는 여러 방법들..
1)
invalidate: 데이터를 무효화한다 refetch가 이루어지도록 한다.
2) refetch가 일어나는 조건을 지정한다 (e.g. window focus 등)
3)staleTime을 지정한다.
App.jsx
import { Posts } from './Posts'; import './App.css'; import { QueryClient, QueryClientProvider } from 'react-query'; // 불러오기 const queryClient = new QueryClient(); // queryClient 생성 function App() { return ( <QueryClientProvider client={queryClient}> // QueryClientProvider 적용 <div className="App"> <h1>Blog Posts</h1> <Posts /> </div> <ReactQueryDevtools /> // 넣기 </QueryClientProvider> ); } export default App;
Post.jsx
import { useState } from 'react'; import { useQuery } from 'react-query'; import { PostDetail } from './PostDetail'; const maxPostPage = 10; async function fetchPosts() { // 쿼리 함수 const response = await fetch( 'https://jsonplaceholder.typicode.com/posts?_limit=10&_page=0' ); return response.json(); } export function Posts() { const [currentPage, setCurrentPage] = useState(0); const [selectedPost, setSelectedPost] = useState(null); // replace with useQuery const { data } = useQuery('posts', fetchPosts ); // useQuery로 쿼리 생성 return ( <> <ul> {data.map((post) => ( // 받아온 data 사용 <li ...
{JSON} Placeholder
- CRUD 가능한 무료 가상 REST API 서버
- 설치 필요 X. 호출만 하면 된다.
data 외에 isLoading, isError, error 등을 받아올 수 있다. isLoading, isError는 boolean 값.Post.jsx
... export function Posts() { const { data, isError, error, isLoading } = useQuery('posts', fetchPosts); if (isLoading) return <h3>Loading...</h3>; // Loading 처리 if (isError) // Error처리 return ( <> <h3>Oops, something went wrong!</h3> <p>{error.toString()}</p> // error메시지 보여주기 </> ); return ( <> <ul> {data.map((post) => ( <li ...
isFetching vs. isLoading
isFetching
- 데이터를 fetch하는 비동기 쿼리 (함수)가 아직 처리중일 때.
- 캐싱 데이터가 있어서 백그라운드에서 fetch 되더라도
true
isLoading
- isFetching + 캐시된 데이터가 없음 (= 이 쿼리를 만든 적이 없음. 처음 만드는 것)
App.jsx
... import { QueryClient, QueryClientProvider } from 'react-query'; import { ReactQueryDevtools } from 'react-query/devtools'; // 불러오기 const queryClient = new QueryClient(); function App() { return ( <QueryClientProvider client={queryClient}> <div className="App"> <h1>Blog Posts</h1> <Posts /> </div> <ReactQueryDevtools /> // 넣기 </QueryClientProvider> ); } export default App;

React Query의 라이프 사이클
- A 쿼리 인스턴스가 mount 됨
- 네트워크에서 데이터 fetch 하고 A라는 query key로 캐싱함
- 이 데이터는
fresh상태에서staleTime(기본값 0) 이후stale상태로 변경됨- A 쿼리 인스턴스가 unmount 됨 = 데이터가
inactive상태로 변경됨- 캐시는
cacheTime(기본값 5분) 만큼 유지되다가 가비지 콜렉터로 수집됨- 만일
cacheTime이 지나기 전에 A 쿼리 인스턴스가 새롭게 mount되면, fetch가 실행되고 fresh한 값을 가져오는 동안 캐시 데이터를 보여줌
fresh -> stale 상태로 변경되는데 걸리는 시간stale 상태일 경우에만 실행됨.fresh 상태일 때는 refetch 일어나지 않음)😀
refetchOnMount설정값이 true(기본값)라면 mount될 때 refetch가 일어나지만...
만일 staleTime을 길게 설정해서 아직 fresh 상태인 채로 unmount 됐다가 다시 mount 될 때까지 staleTime이 끝나지 않았다면?
👉🏽 refetch 되지 않는다! (refetch는 stale 상태일 경우에만 일어난다)
inactive 되고 나서 캐싱된 상태로 남아있는 시간useQuery가 마지막으로 실행된 시점으로부터 계산 (...?)stale 상태가 되어서 쿼리 인스턴스가 unmount 되면 데이터는 inactive 상태로 변경되며, 이후 캐시는 cacheTime 만큼 유지된다.inactive된 시점을 기준으로 cachTime 계산이 시작된다)cacheTime이 지나면 가비지 콜렉터로 수집된다. (이후에는 클라이언트에서 데이터를 보여줄 수 없다. 빈 화면으로 보여짐)cacheTime이 지나기 전에 쿼리 인스턴스가 다시 마운트 되면, 데이터를 fetch하는 동안 캐시 데이터를 보여준다.👉🏽 보통은 빈 화면을 보여주는 것보다 약간 오래된 데이터(stale 된 후 캐싱 상태의 데이터)를 표시하는 것이 낫지만
👉🏽 조금이라도 오래된 데이터를 보여주면 안되는 경우에는cacheTime을 0으로 설정해준다.
Post.jsx
... const { data, isError, error, isLoading } = useQuery('posts', fetchPosts, { staleTime: 2000, cacheTime: 1500000 });
참고
[react-query를 이해하는 몇가지 지식과 질문들]
refetching을 왜 하는가? => 지금 가지고 있는 정보가 fresh하지 않고 stale하니까
refetching 조건을 만족해도 fresh하다면 refetching하지 않는가? => 그렇다.
staleTime이 0이라면 어떻게 되는가? => 곧바로 stale이 되므로 refetching이 요구되는 상황이 오면 무조건 refetching하게 된다.
언제 데이터가 cache되는가? => query를 보내고 데이터를 받아오자마자 cache된다. 그러나 cacheTime은 이 때 발동하지 않는다.
그렇다면 cacheTime은 언제부터 시작인가? => unmount된 시점부터. 즉, inactive된 시점부터 시작한다.
cacheTime이 지나기 전에 다시 쿼리가 발동되면 어떻게 되는가? => cache된 값을 사용하고 background에서 다시 fetching된다.
cacheTime이 지나면 어떻게 되는가? => 메모리에 존재하는 데이터가 GC에 의해 삭제. 따라서 다시 active되면 hard loading한다.
cacheTime이 0이라면 어떻게 되는가? => 매번 GC 당하므로 매번 hard loading을 하게 된다.