๋ถํธ์บ ํ ๋ง์ง๋ง ๊ณผ์ ์ ๋ฆฌ์กํธ ํ๋ก์ ํธ์๋ค.
๊ธฐ๋ณธ์ ์ธ SNS ์๋น์ค์ ๋ํ API๋ฅผ ์ ๊ณต๋ฐ์ ํ ๋์์ธ, ์ํคํ ์ฒ, ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ๊น์ง ๋ชจ๋ ์์ ์ฃผ์ ๋ก ์งํํ๋ ํ๋ก์ ํธ์์ TanStack Query๋ฅผ ์ฌ์ฉํ๋ฉด์ ๋๊ผ๋ ์ด๋ ค์๊ณผ ์ฅ์ ๊ณผ ๋จ์ ๋ฑ ์ฃผ๋์ด ๊ฐ๋ฐ์๋ก์ ๊ฒช์๋ ๊ฒฝํ์ ๊ธฐ๋กํด ๋ณด๊ณ ์ ํ๋ค. ์ฐ์ ํด๋น ๊ฒ์๋ฌผ์์๋ API๋ฅผ ํธ์ถํ๋ ํต์ฌ ๊ธฐ๋ฅ์ธ useQuery์ useMutation์ ๋ํด์ ์์ฑํ๊ณ , ์ฟผ๋ฆฌ ์ ๋ฐ์ดํธ๋ฅผ ํ๊ธฐ์ํ ๋ถ๊ฐ ๊ธฐ๋ฅ๊ณผ, ๋ฌดํ ์คํฌ๋กค, ์๋ฌ๋ฐ์ด๋๋ฆฌ์ ๋ํ ๋ถ๊ฐ ๊ธฐ๋ฅ์ ์ด์ด์ ์์ฑํด๋ณด๊ณ ์ ํ๋ค.
1๏ธโฃ TanStack Query๋?
TanStack Query๋ ์๋ฒ ๋ฐ์ดํฐ์์ ๋๊ธฐํ ๋ฐ ์ ๋ฐ์ดํธํ๋ ์์ ์ ํธํ๊ฒ ํ ์ ์๋๋ก ๋์์ฃผ๋ ์ญํ ์ ํ๋ฉฐ, ๋น๋๊ธฐ ์ฒ๋ฆฌ ๋ก์ง์ ๊ฐ๊ฒฐํ๊ฒ ์ค์ฌ์ค๋ค. ์ฃผ์ ๊ธฐ๋ฅ์ผ๋ก๋ get, post, put ๋ฑ ๋ฉ์๋๋ฅผ ํ์ฉํ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ, ์ ๋ฐ์ดํธ, ์บ์ฑ, ๋ก๋ฉ, ์๋ฌ ์ฒ๋ฆฌ๊ฐ ์๋ค.
React Query๋ผ๋ ์ด๋ฆ์ผ๋ก ๋ ์ ๋ช ํ TanStack Query๋ v3 ๊น์ง๋ React๋ง ์ง์ํ๋๋ฐ, v4๋ถํฐ React๋ฅผ ํฌํจํด์ Vue, Svelte, Solid ์์๋ ์ฌ์ฉ์ด ๊ฐ๋ฅํด์ง๋ฉด์ TanStack Query๋ก ์ด๋ฆ์ด ๋ณ๊ฒฝ๋์๋ค. ์ฌ์ ํ TanStack Query๋ผ๋ ๋ช ์นญ๋ณด๋ค๋ React Query๋ผ๊ณ ์ง์นญ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
TanStack Query ์ ํต์ฌ๊ธฐ๋ฅ์ผ๋ก๋ HTTP์ GET์์ฒญ๊ณผ ๊ฐ์ด ์๋ฒ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ useQuery ํ ์ด ์๊ณ , POST, PUT, DELETE ์์ฒญ ๋ฑ ๋ณ์ด(์ฌ์ด๋์ดํํธ)๋ฅผ ์ ๋ฐํ๋ useMutation ํ ์ด ์๋ค.
2๏ธโฃ TanStack Query์ ์ฅ๋จ์
์ฅ์
- ๋์ผํ ์์ฒญ์ ๋์์ ์ฌ๋ฌ๋ฒ ๋ณด๋ด๋ ์๋์ผ๋ก ๋ฐ์ดํฐ ์์ฒญ์ ํ ๋ฒ๋ง ๋ณด๋ด์ ๋ฉ๋ชจ๋ฆฌ์ ์บ์ ํ๋ฏ๋ก ๋์ผํ ๋ฐ์ดํฐ์ ๋ํ ํ์ ํธ์ถ๋ก ์ธํ ์ค๋ณต ์์ฒญ์ด ๋ฐ์ํ์ง ์์์ ํจ์จ์ ์ด๊ณ ๊ฐํธํ๋ค.
- ๋ฐ์ดํฐ ์บ์ฑ ๊ธฐ๋ฅ์ ์ด์ฉํ๊ธฐ ์ํด Refetch๊ฐ ์ผ์ด๋๋ ์กฐ๊ฑด์ ๋ค์ํ๊ฒ ์ ๊ณตํ๋ค. ์๋์ฐ์ ํฌ์ปค์ค(refetchOnWindowFocus)๋ ๊ฒฝ์ฐ, ๋ง์ดํธ(refetchOnMount) ๋๋ ๊ฒฝ์ฐ, ์ฌ ์ฐ๊ฒฐ(refetchOnReconnect)๋๋ ๊ฒฝ์ฐ ์ธ ๊ฐ์ง๊ฐ ์๋ค.
- ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๋ ๋ก์ง์ด ์ฌํํด์ง๊ณ ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ๊ฐ ์ ์ํ๊ฒ ๋ฐ์๋๋ค.
- ํ์ด์ง๋ค์ด์ , ๋ฌดํ ์คํฌ๋กค, ๋ฐ์ดํฐ ์ง์ฐ ๋ก๋ฉ๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ด ๋ด์ฅ๋์ด ์์ด์ ์ฑ๋ฅ ์ต์ ํํ๊ธฐ ์ข๋ค.
- Devtool์ด ๋ด์ฅ๋์ด ์์ด์ ๋คํธ์ํน ๋๋ ๋ฐ์ดํฐ๋ฅผ ํ์ธํ ์ ์์ด์ ๋๋ฒ๊น ์ ์ฉ์ดํ๋ค.
๋จ์
- ๊ตฌ๊ธ๋ง, gpt(^^;)๋ฅผ ์ฐธ๊ณ ํ๋ ๊ฒฝ์ฐ ์ฌ์ฉ์ค์ธ ๋ฒ์ ๊ณผ ์ผ์นํ๋ ์ ๋ณด์ธ์ง ๊ผญ! ํ์ธํด์ผ ํ๋ค. ๋๋ถ๋ถ์ ์๋ฃ๊ฐ ์ด์ ๋ฒ์ ์๋ฃ์ด๊ธฐ ๋๋ฌธ์ tanstack ๋ฒ์ ์ธ์ง ๊ผญ ํ์ธํ๋ ๊ฒ์ด ์ค์ํ๊ณ , ๋๋๋ก ๊ณต์๋ฌธ์๋ฅผ ์ฐธ๊ณ ํด์ ๊ฐ๋ฐํ๋ ๊ฒ์ด ์ข๋ค.
- ์์ง ๋ฆฌ๋์ค, ๋ฆฌ๋์ค ํดํท๋งํผ ๋ณดํธ์ฑ์ ๊ฐ๊ณ ์์ง๋ ์๊ธฐ ๋๋ฌธ์ ์๋์ ์ผ๋ก ์ฐธ๊ณ ํ ๋งํ ์๋ฃ๊ฐ ๋ถ์กฑํ ํธ์ด๋ค. ๊ทธ๋ฌ๋ ์ฃผ๋์ด ๊ฐ๋ฐ์์๊ฒ๋ ๋ฆฌ๋์ค๋ณด๋ค ํจ์ฌ ๋ค๋ฃจ๊ธฐ ์ฝ๊ธฐ ๋๋ฌธ์ ํ์ฉํด ๋ณด๋ ๊ฒ์ ์ถ์ฒํ๋ค.
3๏ธโฃ ์ค์น ๋ฐ ์ด๊ธฐ ์ธํ
TanStack Query ์ค์น
// npm
npm i @tanstack/react-query
// yarn
$ yarn add react-query
app.js ์ด๊ธฐ ์ค์
- QueryClientProvider ์ปดํฌ๋ํธ๋ฅผ ์ต์๋จ์ ๊ฐ์ธ๊ณ QueryClient ์ธ์คํด์ค๋ฅผ client ์์ฑ์ ๋ฃ์ด์ค๋ค.
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient()
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
)
}
4๏ธโฃ useQuery
- GET์์ฒญ๊ณผ ๊ฐ์ CREAT์์ ์ ํ ๋ ์ฌ์ฉ๋๋ ํ ์ผ๋ก ์ฟผ๋ฆฌํค(queryKey)์ ์ฟผ๋ฆฌํจ์(queryFn)๋ฅผ ํ์๋ก ์ ์ธํด ์ค์ผ ํ๋ค. ์๋ต์ data, ์๋ฌ๋ error, ์ฟผ๋ฆฌ ์ํ๋ฅผ ๋ด๊ณ ์๋ status ๋ฑ์ ๋ฐํ.
- const requestData = useQuery(queryKey, queryFn, Option) ํํ๋ก ๊ตฌ์ฑ.
- useQueries์ useInfiniteQuery ํ ์ useQuery์ ๋ง์ฐฌ๊ฐ์ง๋ก ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ๋ ์ฌ์ฉํ๋ค. ์ฌ๋ฌ ๋ฐ์ดํฐ๋ฅผ ๋ณ๋ ฌ๋ก ๊ฐ์ ธ์์ผ ํ ๋๋ useQueries ํ ์, ๋ฌดํ ์คํฌ๋กค๊ณผ ๊ฐ์ด ๊ณ์ํด์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ผ ํ ๊ฒฝ์ฐ useInfiniteQuery ํ ์ ์ฌ์ฉ.
- ์ฟผ๋ฆฌํค(queryFn)๊ฐ ๋ค๋ฅด๋ฉด ํธ์ถํ๋ API๊ฐ ๋์ผํด๋ ์บ์ฑ์ ๋ณ๋๋ก ๊ด๋ฆฌํ๋ค. Devtool์์๋ ์ฟผ๋ฆฌํค๋ฅผ ์ธ์ํด์ ๋๋ฒ๊น ํ๊ธฐ ๋๋ฌธ์ ๋งค์ฐ ์ค์!
function Example() {
const { isLoading, error, data } = useQuery('repoData', () =>
fetch('https://api.github.com/repos/tannerlinsley/react-query').then(res =>
res.json()
)
)
if (isLoading) return 'Loading...'
if (error) return 'An error has occurred: ' + error.message
return (
<div>
<h1>{data.name}</h1>
<p>{data.description}</p>
<strong>๐ {data.subscribers_count}</strong>{' '}
<strong>โจ {data.stargazers_count}</strong>{' '}
<strong>๐ด {data.forks_count}</strong>
</div>
)
}
- ๋ฐ์ดํฐ ์์ฒญ
data | status ==='success' ์๋ฒ ์์ฒญ์ ๋ํ ๋ฐ์ดํฐ๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์๋ต๋ ์ํ. |
isLoading | status === 'loading' ์ฟผ๋ฆฌ์ ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉฐ ํ์ฌ ๊ฐ์ ธ์ค๋ ์ค์ธ ์ํ. |
isError | status === 'error' ์ฟผ๋ฆฌ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ํ. |
isFetching | true / false ์ฟผ๋ฆฌ์ ๋ฐ์ดํฐ ์ ๋ฌด์ ์๊ด ์์ด ํ์ฌ ๊ฐ์ ธ์ค๋ ์ค์ธ ์ํ. |
error | object ์๋ฒ ์์ฒญ ์คํจ์ ๋ํ ์๋ต. |
- ์ต์
cacheTime | unMount ์ดํ ๋ฉ๋ชจ๋ฆฌ์ ์ธ์ ๊น์ง ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํด์ ์บ์ฑํ ๊ฑด์ง ์ค์ ๊ธฐ๋ณธ 300000 (5๋ถ) |
staleTime | stale(์ ์ ํ์ง ์์) ๋ฐ์ดํฐ๋ฅผ ํจ์นํด์ ์ธ์ ์๋กญ๊ฒ ๊ฐฑ์ ํ ์ง ์ค์ ๊ธฐ๋ณธ 0 |
refetchOnMount | ์ปดํฌ๋ํธ ๋ง์ดํธ์ ์๋ก์ด ๋ฐ์ดํฐ ํจ์นญ ๊ธฐ๋ณธ true |
refetchOnWindowFocus | ๋ธ๋ผ์ฐ์ ๊ฐ ํฌ์ปค์ค ๋ ๋๋ง๋ค ๋ฐ์ดํฐ๋ฅผ ์๋กญ๊ฒ ํจ์น ๊ธฐ๋ณธ true |
refetchInterval | ๋ธ๋ผ์ฐ์ ์ ํฌ์ปค์ค๊ฐ ์์ ๋ ์ง์ ํ ์๊ฐ ๊ฐ๊ฒฉ๋งํผ ๋ฐ์ดํฐ ํจ์นญ ๊ธฐ๋ณธ 0 |
refetchIntervalInBackground | ๋ธ๋ผ์ฐ์ ์ ํฌ์ปค์ค๊ฐ ์์ด๋ ์ง์ ํ ์๊ฐ ๊ฐ๊ฒฉ๋งํผ ๋ฐ์ดํฐ ํจ์นญ ๊ธฐ๋ณธ false |
๐กcacheTime๊ณผ StaleTime, ์ธ์ ์กฐ์ ํ๋ฉด ์ข์๊น?
- StaleTime์ ๊ธฐ๋ณธ ๊ฐ์ด 0์ด๋ฏ๋ก ์๋ต ์ฆ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋ค. ๋ง์ฝ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ์ ๋ณ๊ฒฝ์ด ์์ฃผ ์ผ์ด๋์ง ์๋๊ฒฝ์ฐ ๊ฐ์ ์กฐ์ ํ๋ฉด ๋ถํ์ํ API ํธ์ถ์ ์ค์ผ ์ ์๋ค๋ ์ฅ์ ์ด ์๋ค.
- ์๋ฅผ ๋ค์ด ์ ์ ํ ๋ช ์ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๋ค๋ฉด staleTime์ infinity๋ก ์ค์ ํด์ ๋ถํ์ํ ์์ฒญ์ ๋ฐฉ์งํ๊ณ POST, PUT, DELETE ๋ฑ ๋ณ์ด๋ฅผ ๋ฐ์์ํค๋ ๋ฉ์๋๊ฐ ์คํ๋ ๋๋ง ์ฟผ๋ฆฌ ๋ฌดํจํ๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ๊ฐฑ์ ์ํค๋ ๋ฐฉ๋ฒ์ด ์๋ค.
5๏ธโฃ useMutation
- POST, PUT, DELETE์ ๊ฐ์ ๋ณ๊ฒฝ ๋ฐ ์์ ์์ ์ ์๋ฒ์ ์ ๋ฐ์ดํธํ ๋ ์ฌ์ฉํ๋ ํ ์ด๋ค.
- mutate ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ ์ฝ๋ฐฑ์ ํตํ ํธ๋ฆฌ๊ฑฐ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํจ๋ค.
- const requestData = useMutation(API, mutationFn); ํ์์ผ๋ก ๊ตฌ์ฑ.
- quaryFn๊ณผ ๋ค๋ฅด๊ฒ ๊ธฐ๋ณธ ๊ฐ์ผ๋ก ์ค์ ํด ๋ mutationFn์ด ์๋ค๋ฉด ์๋ตํ ์ ์๋ค.
- useQuery์ ๋์ผํ๊ฒ ์๋ต ๋ฐ์ดํฐ๋ data, ์๋ฌ ์ ๋ณด๋ error ๊ฐ์ฒด๋ก, ์ฟผ๋ฆฌ ์ํ๋ status ๋ก ๋ฐํํ๋ค.
function Example() {
const mutation = useMutation(newTodo => {
return axios.post('/todos', newTodo)
})
return (
<div>
{mutation.isLoading ? (
'Adding todo...'
) : (
<>
{mutation.isError ? (
<div>An error occurred: {mutation.error.message}</div>
) : null}
{mutation.isSuccess ? <div>Todo added!</div> : null}
<button
onClick={() => {
mutation.mutate({ id: new Date(), title: 'Do Laundry' })
}}
>
Create Todo
</button>
</>
)}
</div>
)
}
useMutation(exampleMutation, {
onMutate: (variables) => {
// mutate ํจ์๊ฐ ์คํ๋๊ธฐ ์ ์ ์คํํ ๋ด์ฉ
console.log(variables) // exampleMutation์ ๋ค์ด๊ฐ๋ Arguments
},
onSuccess: (data, variables) => {
// ์ฑ๊ณต์ ์คํํ ๋ด์ฉ
},
onError: (error, variables) => {
// ์๋ฌ์ ์คํํ ๋ด์ฉ
},
onSettled: (data, error, variables, context) => {
// ์ฑ๊ณต or ์๋ฌ ์๊ด ์์ด ์คํํ ๋ด์ฉ
},
})
6๏ธโฃ devtools
- devtools๋ TanStack Query๋ฅผ ์ค์นํ๋ฉด ์๋์ผ๋ก ์ค์น๋๊ณ , ๋ณ๋ค๋ฅธ ์ค์ ์์ด QueryClientProvider ๋ฒ์ ๋ด์ ReactQueryDevtools๋ฅผ ์ ์ธํ๋ฉด ๋๋ค.
- ๊ฐ ์ฟผ๋ฆฌํค์ ๋ํ ๋ฐ์ดํฐ์ ์ํ๋ฅผ ์ฝ๊ฒ ํ์ธํ ์ ์๋ค.
- devtool์ ๋ํ ์์ธํ ๊ณต์๋ฌธ์ ์ค๋ช ์ ์ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ !
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
function App() {
return (
<QueryClientProvider client={queryClient}>
{/* The rest of your application */}
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
)
}
๐ฉ๐ป๐ป ๊ฒฐ๋ก
- TanStack Query๋ ์์ ์ธ๊ธํ๋ ์ฟผ๋ฆฌ๋ค ๋ง๊ณ ๋ ๋ค์ํ ์ฟผ๋ฆฌ๋ฅผ ์ ๊ณตํ๊ณ ํจ์ฌ ๋ค์ํ ๊ธฐ๋ฅ์ด ์๋ค.
- ๋ฌด์๋ณด๋ค ๋น๋๊ธฐ(API ํธ์ถ ๋ฑ) ์์ ์ ์ต์ ํ๋์ด์๋ TanStack Query๋ฅผ ์ฌ์ฉํ ๋์๋ ๋ฒ์ ์ ์ ์ํ์ฌ ์ฐธ๊ณ ์๋ฃ๋ฅผ ํ์ฉํ๋ ๊ฒ ์ค์ํ๊ณ ๊ณต์๋ฌธ์๋ฅผ ํ์ฉํ๋ ๊ฒ ์ข๋ค.
- TanStack Query ์ ํต์ฌ๊ธฐ๋ฅ์ผ๋ก๋ HTTP์ GET์์ฒญ๊ณผ ๊ฐ์ด ์๋ฒ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ useQuery ํ ์ด ์๊ณ , POST, PUT, DELETE ์์ฒญ ๋ฑ ๋ณ์ด(์ฌ์ด๋์ดํํธ)๋ฅผ ์ ๋ฐํ๋ useMutationํ ์ด ์๋ค.