React Query μμΈν μμ보기
React Queryλ ν¬κ² 2κ°μ§λ‘ λλ©λλ€.
- Query : μλ² λ°μ΄ν°λ₯Ό κ°μ Έμ€λ κ²
- Mutation : μλ² λ°μ΄ν°μ κ°μ λ°κΎΈκ±°λ μΆκ° λλ μμ νλκ²
Query
π¬ useQuery κΈ°λ³Έ μ€λͺ
GET μμ²κ³Ό λΉμ·νκ² μλ² λ°μ΄ν°λ₯Ό κ°μ Έμ€κΈ° μν΄μ useQuery
λΌλ hookμ΄ μ¬μ©λ©λλ€. μ΄ useQuery
λ₯Ό μ¬μ©ν λ λκ°μ§λ₯Ό μ£Όμν΄μΌ ν©λλ€.
const data = useQuery(queryKey, queryFn)
- queryKey :
useQuery
λ§λ€ λ°°μ΄ ννλ‘ λΆμ¬λλ κ³ μ νkey
κ°μ λλ€. μ΄queryKey
λ₯Ό ν΅ν΄μ λ€λ₯Έ mutation functionμ΄λ λ€λ₯Έ κ³³μμλ ν΄λΉ 쿼리μ κ²°κ³Όλ₯Ό κΊΌλ΄μ€λκ²μ΄ κ°λ₯ν©λλ€.React query
λ μ΄queryKey
λ‘ μΊμ± κ΄λ¦¬λ₯Ό νμ¬ λ°μ΄ν°λ§λ€ κ³ μ νkey
κ°μ μ§μ νλκ² μ€μν©λλ€. λ λμκ°μ νΉμ ν λ°μ΄ν°λ₯Ό κ°μ Έμ€κΈ° μν΄μ λ°μ΄ν°μ μμ΄λλ νμν νν°λ§ 쑰건μ λ°°μ΄ ννλ‘ λ³΄λ΄μ€μ μμ΅λλ€.
/posts => ["posts"]
/posts/1 => ["posts", post.id]
/posts?authorId=1 => ["posts", {authorId : 1}]
/posts/2/comments => ["posts", post.id, "comments"]
- queryFn :
Promise
μ²λ¦¬κ° μ΄λ€μ§λ ν¨μλ‘ μλ²μ apiλ₯Ό μμ²νλ μ½λμ λλ€.
useQuery
λ λΉλκΈ°λ‘ μλν©λλ€. λ§μ½ μ¬λ¬κ°μ useQuery
κ° ν μ»΄ν¬λνΈμμ μ¬μ©λ κ²½μ° νλκ° λλλ€μ λ€μ useQuery
κ° μ€νλλ κ²μ΄ μλ μ¬λ¬κ°μ useQuery
κ° λμμ μ€νλ©λλ€.
π useQuery return κ°
const queryClient = useQueryClient();
const { data, isLoading, isError, error, isSuccess, status} = useQuery({
queryKey: ["posts"],
queryFn: () => wait(1000).then(() => [...POSTS]),
});
if (isLoading || status === 'loading') return <div>...isLoading</div>;
if (isError || status === 'error') {
return <pre>{JSON.stringify(error)}</pre>;
}
return (
<div>{data.map((data) => (<p key={data.id}>{data.title}</p>))}</div>
)
- data : queryFn ν¨μλ₯Ό λλν κ²°κ³Όκ°μ λνλ λλ€.
- isLoading : boolean ννμ κ°μΌλ‘ μλ²μμ λ°μ΄ν°λ₯Ό λ°μμ€λ λμ λ‘λ© νλ©΄μ 보μ¬μ£Όκ³ μΆλ€λ©΄ μ΄ κ°μ΄ μ μ©νκ² μ°μΌκ²μ λλ€.
- isError : boolean ννμ κ°μΌλ‘ μ¬λ¬λ²μ μλλμ κ³μ queryFn ν¨μκ° μλ¬λ₯Ό λΈλ€λ©΄ μ΄ κ°μΌλ‘ μλ¬λ₯Ό νμ ν μ μμ΅λλ€.
- error : μλ¬κ° μκ²Όμλ νλ©΄μ μλ¬ λ©μΈμ§λ₯Ό 보μ΄κ² νκ³ μΆκ±°λ νμΈνκ³ μΆλ€λ©΄ μ΄ κ°μ μΈμ μμ΅λλ€.
- isSuccess : boolean ννμ κ°μΌλ‘ μ±κ³΅μ μΌλ‘ λ°μ΄ν°λ₯Ό λ°μμλμ§λ₯Ό νμΈν μ μμ΅λλ€.
- status :
error
,loading
,success
μ€ κ°μ μνλ₯Ό νμΈν μ μμ΅λλ€. - fetchStatus :
fetching
: νμ¬ λ°μ΄ν°λ₯Ό κ°μ§κ³ μ€λ μ€μΌλλ₯Ό λ»ν©λλ€idle
: νμ¬ μ무κ²λ νμ§ μκ³ μκ±°λ λ°μ΄ν°λ₯Ό κ°μ Έμ¨ νλ₯Ό λ»ν©λλ€.paused
: λ°μ΄ν°λ₯Ό κ°μ Έμ€λμ€μ μΈν°λ·κ³Ό λκ²Όκ±°λ μ΄λ ν μ΄μ λ‘ λ©μ·μ λλ₯Ό λ»ν©λλ€.
π useQueryλ₯Ό μ¬μ©ν΄ fetching ν λμ κ³Όμ
-
νμ΄μ§μμ μ»΄ν¬λνΈμ
useQuery
κ° μμλuseQuery
λ μ€νλλ©° λ°μ μν©λ€μ΄ μΌμ΄λ λ λ€μ μ€νλ©λλ€.- νμ΄μ§ μλ‘κ³ μΉ¨
- ν νμ΄μ§μμ λ€λ₯Έ νμ΄μ§λ‘ λμ΄κ°λ
- λ§μ°μ€ ν¬μ»€μ€λ₯Ό λ€λ₯Έ κ³³μ λλ€κ° λ€μ νμ΄μ§λ‘ λμκ°λ
- μΈν°λ·μ΄ λκ²Όλ€κ° λ€μ λμμ€λ λμμ νμ΄μ§λ₯Ό 보μ¬μ€λ
-
QueryKey
λ₯Ό μ¬μ©ν΄ λ°μ΄ν°κ°stale
μΈμ§λ₯Ό μμλ³Έλ€μrefetch
λ₯Ό ν©λλ€. -
refetch
λ λ°μ΄ν°λ₯Ό νλ©΄μ 보μ¬μ€λλ€.
μ μΌ μ²μμ νμ΄μ§λ₯Ό λ‘λ©ν λ
fetchStatus : fetching
status : loading
λ°μ΄ν°λ₯Ό μ±κ³΅μ μΌλ‘ κ°μ Έμμ λ
fetchStatus : idle
status : success (μ€ν¨ν κ²½μ° "error")
λ€λ₯Έ νμ΄μ§λ‘ λμ΄κ°λ λκ°μ λ°μ΄ν°λ₯Ό λμ΄κ°λ νμ΄μ§μμλ λΆλ₯Ό κ²½μ° (Refetching)
fetchStatus : fetching
status : success (μ€ν¨ν κ²½μ° "error")
π useQueryμμ μμ£Ό μ¬μ©λλ μ΅μ
const { data, isLoading, isError, error, isSuccess, status} = useQuery({
queryKey: ["posts", postQuery?.data?.postId],
queryFn: getPosts,
enabled: postQuery?.data.postId !== null,
staleTime : 1000,
refetchInterval : 1000,
});
enabled : μμμ λ§νλ―μ΄ useQuery
λ λΉλκΈ°λ‘ μλν©λλ€. λ§μ½ μ¬λ¬κ°μ useQuery
λ₯Ό ν μ»΄ν¬λνΈμμ λκΈ°λ‘ μλνκ³ μΆλ€λ©΄ enable
λ₯Ό μ¬μ©ν μ μμ΅λλ€. boolean ννμ 쑰건μ λ£μ΄μ£Όλ©΄μ μ‘°κ±΄μ΄ true
μΌλ useQuery
λ₯Ό μλμν΅λλ€.
staleTime : λ°μ΄ν°λ₯Ό fresh
μνμμ stale
μνλ‘ μ νλ λκΉμ§μ μκ°μ μ ν΄μ€ μ μμ΅λλ€. λ§μ½ 5λΆμ μ§μ ν΄μ€λ€λ©΄ 5λΆλμμ λ°μ΄ν°κ° fresh
μνλ₯Ό μ μ§ν κ²μ΄λ©° fresh
μνμ λ°μ΄ν°λ νμ cacheμμ μ½μ΄μ¨λ€λ κ²μ λ»ν©λλ€.
refetchInterval: milisecond λ¨μμ μκ°μΌλ‘ μ§μ ν μκ°λ§λ€ λ°μ΄ν°λ₯Ό refetch ν μ μμ΅λλ€. λ§μ½ 1000λ₯Ό μ§μ ν΄μ£Όμλ€λ©΄ 1μ΄λ§λ€ νλ²μ© λ°μ΄ν°λ₯Ό refetch ν΄μ€λλ€.
π‘ staleμ΄λ? React queryλ μΊμ±λ dataλ₯Ό
stale
ν μνλ‘ μ¬κΉλλ€. μ¬κΈ°μstale
μ "μ μ νμ§ μλ€"λΌλ λ»μ΄ μλλ°μ. μ΄stale
ν dataλ μ΅μ νκ° νμν λ°μ΄ν°λΌλ μλ―Έλ‘ μ»΄ν¬λνΈκ° λ§μ΄νΈλ μ λ°μ΄νΈλλ©΄ refetchκ° λ©λλ€.
Mutation
π¬ useMutation κΈ°λ³Έ μ€λͺ
POSTλ PUT μμ²κ³Ό λΉμ·νκ² μλ² λ°μ΄ν°μ κ°μ λ°κΎΈκ±°λ μΆκ° λλ μμ νκΈ° μν΄μ useMutation
μ΄λΌλ hookμ΄ μ¬μ©λ©λλ€. λ°λ propsλ€μ΄ μμ useQuery
μ λμΌνμ§λ§ κ·Έ μΈμ λ λ€λ₯Έ νλμ mutate
λλ mutateAsync
μ΄λΌλ propsλ₯Ό λ°μ΅λλ€. mutate
λλ mutateAsync
λ ν¨μ ννμ΄λ©° useMutation
μ μ€νν μ μκ² λμμ€λλ€.
-
mutationFn : queryFnκ³Ό κ°μ΄ Promise μ²λ¦¬κ° μ΄λ€μ§λ ν¨μλ‘ μλ²μ apiλ₯Ό μμ²νλ μ½λμ λλ€. νλμ propsλ₯Ό λ°μμ μμΌλ©° μ΄ κ°μ ν¨μμ μ λ¬νμ¬ μ¬μ©ν μ μμ΅λλ€.
-
onSuccess : μμλλ‘ μλνμλ μ€νλλ ν¨μμ λλ€.
onSuccess
λ₯Ό μ¬μ©νμ§ μλλ€λ©΄mutationFn
μ΄ λλλ νμλ νλ©΄μ λ°λ κ²°κ³Όκ° λνλμ§ μμκ²λλ€. κ·Έ μ΄μ λ‘λ mutationμ λ¨μνuniquekeyname
μ κ°μ§κ³ μλ κ°μ λ°κΎΈμ΄λ²λ¦΄ λΏ λ€μfetch
ν΄μ€μ§ μκΈ° λλ¬Έμ λλ€.onSuccess
κ° μ€νλ λ μΈκ°μprops
λ₯Ό λ°λλ°μ.data
λ κ²°κ³Όκ°μ λνλ΄κ³props
λmutationFn
μμ μ λ¬νλ κ°κ³Ό κ°μ κ°μ λ°μ΅λλ€. λ§μ§λ§μΌλ‘context
λonMutate
ν¨μμμ return νλ κ°μ λ»ν©λλ€.queryClient.invalidateQueries
: queryKeyλ₯Ό μ¬μ©ν΄ κ°μ λ€μ refetchλ₯Ό ν μ μμ΅λλ€.
-
onError : μμλλ‘ μλνμ§ μμμλ μ€νλλ ν¨μμ λλ€.
-
onSettled : μμ
onError
κ³ΌonSuccess
μ λ€λ₯΄κ² 4κ°μ propsλ₯Ό λ°μλ΄λ©°data
μerror
μ λ€ μ λ¬ λ°μμ μμ΅λλ€. -
onMutate : μμ μΈκ°μ ν¨μμ λ€λ₯΄κ² propsλ₯Ό νλλ§ μ λ¬ λ°λ ν¨μ μ λλ€. μ΄ ν¨μλ
mutationFn
μ΄ μλλκΈ° μ μ μ€νλλ©° μ¬κΈ°μ 보λ΄λ κ°μonSuccess
μcontext
λ‘ μ λ¬λ©λλ€. λ°μ΄ν°λ₯Ό μ¬λ¬λ² μμ±λλ λ³κ²½λλκ±Έ λ§κΈ°μν΄ μ΄ ν¨μλ μμλλ‘ μλνμ§ μμλ λ€μ μλλ₯Ό ν΄λ³΄λ € νμ§ μμ΅λλ€. νμ§λ§retry
λ₯Ό ν΅ν΄ λ€μ μλ ν΄λ³Ό μλ₯Ό μ§μ ν μ μμ΅λλ€.
const queryClient = useQueryClient();
const {data, error, status,isIdle, isSuccess, isError, mutate } =
useMutation({
mutationFn: (props) => wait(1000).then(() => POSTS.push({ id: 1, props })),
onSuccess: (data, props, context) => {
queryClient.invalidateQueries(["posts"]);
},
onError: (error, props, context) => {
...
},
onSettled: (data, error, props, context) => {
...
},
retry: 3,
onMutate: props => {
return {key:"value"}
},
});
return (
<button onClick={()=> mutate('New post') } />
<button onClick={()=> mutateAsync('New post').then(()=>{...}) } />
)
Devtool
React Query Devtoolsλ React Queryμ μ₯μ μ€μ νλμΈ κ°λ ₯ν λ΄μ₯ κ°λ° λꡬμ λλ€. μ¬μ©μ€μΈ λͺ¨λ 쿼리 μνλ€μ μκ°ννμ¬ νμΈν μ μκ² λμμ£Όκ³ μλ¬κ° μκΈ°κ±°λ μμλλ‘ μλνμ§ μλ κ²½μ° λ¬Έμ λ₯Ό ν΄κ²°ν μ μκ² λμμ€λλ€.
π μ€μΉλ°©λ²
npm i @tanstack/react-query-devtools
yarn add @tanstack/react-query-devtools
π μ¬μ©λ°©λ²
react-query
κ° μ 곡νλ QueryClientProvider
μ¬μ΄μ ReactQueryDevtools
λ₯Ό λ£μ΄μ€μΌ ν©λλ€. μ¬κΈ°μ propsλ‘ clientλ₯Ό μ λ¬ν΄μ€μΌ νλλ° QueryClient
μ μΈμ€ν΄μ€λ₯Ό μ λ¬ν΄μ£Όλκ²μΌλ‘ λ§μ‘±μν¬ μ μμ΅λλ€.
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { QueryClient, QueryClientProvider } from 'react-query';
const queryClient = new QueryClient();
...
return
<QueryClientProvider client={queryClient}>
<ReactQueryDevtools initialIsOpen={false} position='bottom-right' />
</QueryClientProvider>
// initialIsOpen : openλ μ±λ‘ μμ
// position : devtoolsλ₯Ό μ΄ μ μλ logo μμΉ - μ°μΈ‘ νλ¨μΌλ‘ μ§μ