React Query๋ React์ ์ข
์์ ์ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ฉฐ,
React ์ ํ๋ฆฌ์ผ์ด์
์์ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๊ณ ๊ฐ์ ธ์ค๋ ๋ฐ ๋งค์ฐ ์ ์ฉํ๋ค.
Redux์์ ์๋ฒ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ๋ post, put, patch ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ฉด,
๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ณ ๋ค์ get๋ฉ์๋ ์์ฒญ์ ํตํด ์๋ฒ์์ ๋๊ธฐํ๊ฐ ํ์ํด์ง๋ค.
์ด๋, React Query์ invalidateQueries๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
React Query๋ get์ผ๋ก ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ state์ฒ๋ผ ๊ฐ์ง๊ณ ์๊ณ ,
setState(post, put, patch)ํ๋ฉด invalidateQueries๋ฅผ ํธ์ถํด์
์๋ก์ด ๋ฐ์ดํฐ๋ก refetching ํ ์ ์๋ค.
์ฆ, React Query๋ ์๋ฒ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ๋, API ์์ฒญ์ ๋ณด๋ด๊ณ ์๋ต์ ๋ฐ์์ค๋ ๊ฒ์ ๋ฌผ๋ก , ์บ์๋ฅผ ํตํด ํด๋ผ์ด์ธํธ ์ธก์์๋ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ ์ ์๋ค. ์ด๋ฅผ ํตํด ์๋ฒ์์ ๋๊ธฐํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค๋ ๊ฒ.
npm install react-query
// ๊ฐ์ ธ์ค๊ธฐ
import { QueryClientProvider, QueryClient } from "react-query"
// ์ฟผ๋ฆฌ ํด๋ผ์ด์ธํธ๋ฅผ ์์ฑ
// ์ฟผ๋ฆฌ ํด๋ผ์ด์ธํธ๋ ์ฟผ๋ฆฌ์ ์๋ฒ์ ๋ฐ์ดํฐ ์บ์๋ฅผ ๊ด๋ฆฌํ๋ ํด๋ผ์ด์ธํธ์
const queryClient = new QueryClient();
function App () {
<QueryClientProvider client={queryCient}>
<Header />
<Main />
<Footer />
</QueryClientProvider>
}
์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด ์ฌ์ฉํ๋ค.
useQuery์ ์ฒซ ๋ฒ์งธ ์ธ์ โ QueryKey(์ ๋ํฌํด์ผ ํจ)
useQuery์ ๋ ๋ฒ์งธ ์ธ์ โ QueryFunction(๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๋ ๋น๋๊ธฐ ํจ์)
/* Main.js */
// userQuery ๊ฐ์ ธ์ค๊ธฐ
import { useQuery } from "react-query"
const Main = () => {
// ์๋ฒ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ์ค๋ ํจ์
const getInfo = () => {
return axios.get("/user").then((res) => res.data)
}
// ๊ตฌ์กฐ๋ถํดํ ๋น
const { data, isLoading, isError } = useQuery("keynameUserInfo", getInfo);
if (isError) return <span>ERROR</span>
if (isLoading) return <span>Loading...</span>
return (
<>
<span>{data?.userName}</span>
</>
)
}
export default Main;
์ฌ๊ธฐ์ ์ฌ์ฉํ data๋ axios๋ก ๊ฐ์ ธ์จ data์ด๋ฉฐ,
isLoading๊ณผ isError๋ queryFn์ ์คํํ๋ ๋์์
๋ก๋ฉ, ์๋ฌ ์ฌ๋ถ์ ๋ฐ๋ผ boolean ๊ฐ์ผ๋ก ๋ฐ์์ฌ ์ ์๋ค.
useQuery์์ ๋ฐํ๋๋ ๊ฐ์ฒด๋ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์๋ค.
const result = useQuery("keynameUserInfo", getInfo);
console.log(result);
// ์ฝ์์ฐฝ์ ์ฐํ
data,
dataUpdatedAt,
error,
errorUpdatedAt,
failureCount,
isError,
isFetched,
isFetchedAfterMount,
isFetching, // ๋น๋๊ธฐ์ฟผ๋ฆฌ๊ฐ ํด๊ฒฐ๋์ง ์์์
isIdle,
isLoading, // ์ฟผ๋ฆฌํจ์๊ฐ ํด๊ฒฐ๋์ง ์์๊ณ , ์บ์๋ ๋ฐ์ดํฐ๋ ์๋ค
isLoadingError,
isPlaceholderData,
isPreviousData,
isRefetchError,
isRefetching,
isStale,
isSuccess,
refetch,
remove,
status,
useQuery์ ๋ค๋ฅด๊ฒ mutation์
๋ฐ์ดํฐ๋ฅผ ์์ฑ, ์
๋ฐ์ดํธ, ์ญ์ ํ ๋ ์ฌ์ฉ๋๋ค.
invalidateQueries๋ queryKey ๊ฐ ํน์
ํค๋ค์ ๋ฐฐ์ด์ ์ธ์๋ก ๋ฐ์ผ๋ฉฐ, ํด๋น ์ฟผ๋ฆฌ๋ค์ ๋ฌดํจํ์ํจ๋ค.
(๋ฌดํจํํ ๋ชจ๋ ์ฟผ๋ฆฌ๊ฐ ์ฌํธ์ถ๋๋ ๊ฒ์ด ์๋๋ผ,
ํ๋ฉด ๋ ๋๋ง์ ์ฐ๊ด๋ ์ฟผ๋ฆฌ๋ง ์ฌํธ์ถ๋๊ณ
๋๋จธ์ง๋ stale ์ํ๋ก๋ง ์ ํ๋๋ ๊ฒ์)
import { useQuery, useMutation, useQueryClient } from "react-query"
const Main = () => {
...
const { data } = useQuery("keynameUserInfo", getInfo);
// ์ฟผ๋ฆฌ ํด๋ผ์ด์ธํธ ๊ฐ์ ธ์ค๊ธฐ
const queryClient = useQueryClient();
// ์๋ฒ์ ๋ฐ์ดํฐ๋ฅผ ์
๋ฐ์ดํธํ๋ ํจ์
const updateInfo = (userName) => {
return axios.put(`/update-username?username=${username}`)
}
// useMutation ์ฒซ๋ฒ์งธ ์ธ์ => QueryFunction
// useMutation ๋๋ฒ์งธ ์ธ์ => ์ต์
const mutation = useMutation(updateInfo, {
onSuccess: () => {
// ๋ฎคํ
์ด์
์ด ์ฑ๊ณต์ ์ผ๋ก ๋๋ฌ์๋,
// 'keynameUserInfo' ํค๊ฐ ๊ฐ์ง ๋ชจ๋ ์ฟผ๋ฆฌ๋ฅผ ๋ฌดํจํ์ํด
queryClient.invalidateQueries("keynameUserInfo");
},
})
mutation.mutate("๋ณ๊ฒฝํ _์๋ก์ด_์ ์ _์ด๋ฆ")
return (
<>
<span>{data?.userName}</span>
</>
)
}
/*
* useMutation์์ ๊ฐ์ฅ ๋ง์ด ์ฐ๋ 3๊ฐ์ง ์ต์
* - optimisticUpdate: ์๋ฒ๋ก ์ ์ก๋๊ธฐ ์ ์, ์ด๋ฏธ ๋ณํ๋ ์ํ๋ฅผ ์ฆ์ UI์ ๋ฐ์ํจ
* - invalidateQueries: ๋ฎคํ
์ด์
์ด ์ฑ๊ณต์ ์ผ๋ก ์คํ๋ ํ, cache์์ query๋ฅผ ์ญ์
* - setQueryData: ๋ฎคํ
์ด์
์ด ์ฑ๊ณต์ ์ผ๋ก ์คํ๋ ํ, cache์ ์๋ query ๊ฒฐ๊ณผ๋ฅผ ์
๋ฐ์ดํธ
*/
/*
* useMutation hook์์ ์ ๊ณตํ๋ ์์ฑ
* - onMutate: ๋ฎคํ
์ด์
์ด ์คํ๋๊ธฐ ์ ์ ์คํ
* - onError: ๋ฎคํ
์ด์
์ด ์คํจํ ๊ฒฝ์ฐ ํธ์ถ
* - onSettled: ๋ฎคํ
์ด์
์ด ์๋ฃ๋ ํ์ ํธ์ถ๋๋ ํจ์
* - onSuccess: ๋ฎค๋ฐ์ด์
์ด ์ฑ๊ณตํ ๊ฒฝ์ฐ ํธ์ถ๋๋ ํจ์
*/
์ด ๋ ์ต์ ์ ๊ฐ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ธ์ ๊ฐ์ ธ์ฌ์ง์ ์ผ๋ง๋ ์ค๋ ์ ์งํ ์ง๋ฅผ ์ ์ดํ๋ค.
staleTime
๋ฐ์ดํฐ๊ฐ ์บ์์์ ๋ง๋ฃ๋์์ง๋ง ์ฌ์ ํ ์ ํจํ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ ๋๋ง์ ํ์ฉํ๋ ์๊ฐ(๋ฐ๋ฆฌ ์ด)์ ์ค์ ํ๋ค. ์ด ์๊ฐ ๋ด์๋ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ ์ค์ง ์๊ณ ์บ์๋ ๋ฐ์ดํฐ๋ฅผ ๊ณ์ ์ฌ์ฉํ๋ค. ๋ฐ๋ผ์ ์ ํ๋ฆฌ์ผ์ด์
์ฑ๋ฅ์ ํฅ์์ํค๊ณ ๋ถํ์ํ ๋คํธ์ํฌ ์์ฒญ์ ๋ฐฉ์งํ ์ ์๋ค.
// ์ฌ์ฉ ์์ - useQuery์์ ๊ฐ๋ณ์ ์ผ๋ก ์ค์ ํจ
// (queryClient์์ ์ ์ญ์ ์ผ๋ก ์ค์ ๋ ๊ฐ๋ฅ)
const { data } = useQuery("keynameUserInfo", getInfo, { staleTime: Infinity });
cacheTime
๋ฐ์ดํฐ๊ฐ ์บ์์์ ๋ง๋ฃ๋์ด ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ผ ํ๋ ์๊ฐ(๋ฐ๋ฆฌ ์ด)์ ์ค์ ํ๋ค. ์ด ์๊ฐ ์ดํ์๋ ์บ์๋ ๋ฐ์ดํฐ๊ฐ ๋ง๋ฃ๋๊ณ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ์
๋ฐ์ดํธํ๋ค.
๋ณดํต ์บ์ ๋ฐ์ดํฐ๋ฅผ ์ค๋ ์ ์งํ๊ณ ๋ถํ์ํ ๋คํธ์ํฌ ์์ฒญ์ ์ค์ด๊ธฐ ์ํด
staleTime์ ๋ ๊ธธ๊ฒ, cacheTime์ ๋ ์งง๊ฒ ์ค์ ํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ด๋ค.
์ ์ญ์ผ๋ก Suspense๋ฅผ ์ค์ ํด๋ ๋๊ณ
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const queryClient = new QueryClient({
defaultOptions: {
queries: {
suspense: true,
},
},
})
function App() {
return (
<QueryClientProvider client={queryClient}>
<Main />
</QueryClientProvider>
)
}
๊ฐ๊ฐ์ useQuery์ ์ค์ ํด ์ค๋ ๋๋ค.
import { useQuery } from '@tanstack/react-query'
useQuery(queryKey, queryFn, { suspense: true })
Router์์ suspense์ react-query๋ ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ ์ ์๋ค.
Home๊ณผ Aboute ์ปดํฌ๋ํธ์ useQuery์์ ๋ฝ์๋ธ
isLoading์ผ๋ก ๋ฐ๋ก ์ฒ๋ฆฌํ์ง ์์๋ ๋ก๋ฉ ์ฒ๋ฆฌ๊ฐ ์ ๋๋ค.
import { BrowserRouter, Routes, Route } from "react-router-dom"
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { Suspense } from "react"
...
const queryClient = new QueryClient({
defaultOptions: {
queries: {
suspense: true,
},
},
})
function Loading = () => {
return <div>Loading...</div>
}
function App() {
return (
<QueryClientProvider client={queryClient}>
<Suspense fallback={<Loading />}>
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
</Suspense>
</QueryClientProvider>
)
}
ํ์ง๋ง react-query์์ Suspense๋ฅผ ์ฌ์ฉํ๋ฉด ๋ณ๋ ฌ์ ์ผ๋ก ๋์ํ์ง๋ ์๋๋ค.
๋ณ๋ ฌ์ ์ผ๋ก ๋์์ํค๊ธฐ ์ํด์ useQuery๊ฐ ์๋๋ผ useQueries๋ผ๋ ํ
์ ์ฌ์ฉํด์ผ ํ๋ค.
โ๏ธ์ฐธ๊ณ ) ์ฌ๋ฌ ๊ฐ์ query๋ฅผ ๋ณ๋ ฌ๋ก ์คํ์ํฌ ์ ์๊ฒ ํด์ฃผ๋ useQueries๋ Suspense์ ํจ๊ป ์ฌ์ฉ ์ ์ ์์ ์ผ๋ก ๋์ํ์ง ์๋ ์ด์๊ฐ ์์์ง๋ง, ์ด๋ฒ v4.5.0 ํจ์น์ ํด๋น ์ฌํญ์ด ์์ ๋์๋ค.
import { useQueries } from "react-query"
const results = useQueries({
queries: [
{ queryKey: ["getUser"], queryFn: getUser, staleTime: Infinity},
{ queryKey: ["getHistory"], queryFn: getHistory, staleTime: Infinity}
]
})
๐ซSuspense ์ฌ์ฉ๋ฒ ๋ณด๋ฌ๊ฐ๊ธฐ
๐ React Query ๊ณต์๋ฌธ์ ๋ณด๋ฌ๊ฐ๊ธฐ
๐ Reacr-query(๊ณต์๋ฌธ์) - Suspense ๏ผ Parallel Queries ๏ผ useQueries