0%

React Query를 이용해 api 연동시키기

React Query 란?

리액트용 data-fetching 라이브러리로,

리액트 어플리케이션에서 서버의 상태를 fetching, caching, synchronizing, updating 한다.

react query는 다음과 같이 4가지 상태를 반환하는데, 반환 상태에 따라 렌더링을 다르게 처리하기 용이하단느 장점이 있다.

  1. isIdle : status === ‘idle’로, fresh/reset된 상태
  2. isLoading : status === ‘loading’으로, mutation이 진행 중인 상태
  3. isError : status === ‘error’로, mutation이 error를 발생시킨 상태
  4. isSuccess : status === ‘success’로, mutation이 성공하여 data 이용이 가능한 상태

설치하기

1
2
3
$ npm i react-query
# or
$ yarn add react-query

기본 예시

App.tsx

1
2
3
4
5
6
7
8
9
10
11
import { QueryClient, QueryClientProvider, useQuery } from 'react-query'

const queryClient = new QueryClient()

export default function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
)
}
  • 가장 상단 App.js 에서 최상단 컴포넌트로 QueryClientProvider 을 전달한다.

  • 해당 Provider context의 props로 queryClient 객체를 전달한다.

Example.tsx

1
2
3
4
5
6
function Example() {
const { isLoading, error, data } = useQuery('repoData', () =>
fetch('https://api.github.com/repos/tannerlinsley/react-query').then(res =>
res.json()
)
)
  • useQuery
    • query key
    • fetch , axios 등을 이용한 CRUD 함수 를 전달한다.

useQuery 를 통해 isLoading , error , data 등을 받아 렌더링 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  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>
)
}
  • isLoading 일 때는 로딩 렌더링
  • error 일 때는 에러 렌더링
  • 이 외, data 를 정상적으로 받아온 경우 컴포넌트를 알맞게 렌더링

useQuery

useQuery 가 반환하는 프로퍼티와 받는 매개변수는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
const {
data,
dataUpdatedAt,
error,
errorUpdatedAt,
failureCount,
isError,
isFetched,
isFetchedAfterMount,
isFetching,
isIdle,
isLoading,
isLoadingError,
isPlaceholderData,
isPreviousData,
isRefetchError,
isStale,
isSuccess,
refetch,
remove,
status,
} = useQuery(queryKey, queryFn?, {
cacheTime,
enabled,
initialData,
initialDataUpdatedAt
isDataEqual,
keepPreviousData,
notifyOnChangeProps,
notifyOnChangePropsExclusions,
onError,
onSettled,
onSuccess,
queryKeyHashFn,
refetchInterval,
refetchIntervalInBackground,
refetchOnMount,
refetchOnReconnect,
refetchOnWindowFocus,
retry,
retryOnMount,
retryDelay,
select,
staleTime,
structuralSharing,
suspense,
useErrorBoundary,
})

// or using the object syntax

const result = useQuery({
queryKey,
queryFn,
enabled,
})

이를 사용한 예시는 다음과 같다.

먼저, useQuery에 전달할 getCategoryDetail api 함수를 작성해보자.

1
2
3
4
export const getCategoryList = async () => {
const data = await axios.get(`/api/category/`);
return data.data.result as CategoryList;
};

이제 해당 함수를 useQuery에 전달하여 데이터를 받아보자.

1
const { isLoading, error, data: categoryList } = useQuery('categoryList', getCategoryList);

여기서 categoryListquery key 이며, getCategoryList 를 통해 받아온 데이터는 isLoading , error , data 등을 담은 객체에 저장된다.

여기서 data: categoryList 로 데이터 변수명을 설정하여 컴포넌트를 알맞게 렌더링하면 된다!

useMutation

useMutation 이 반환하는 프로퍼티와 받는 매개변수는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const {
data,
error,
isError,
isIdle,
isLoading,
isPaused,
isSuccess,
mutate,
mutateAsync,
reset,
status,
} = useMutation(mutationFn, {
mutationKey,
onError,
onMutate,
onSettled,
onSuccess,
useErrorBoundary,
})

mutate(variables, {
onError,
onSettled,
onSuccess,
})

이제 useMutation을 사용해보자!

1
2
3
4
5
6
7
8
9
10
export const postItem = async (data: Item) => {
const data = await instance.post(
`/api/items`,
{
category_id: `${data.category_id}`,
item_name: `${data.candy_name}`,
},
);
return data.data.result as NewItem;
};

위와 같이 정의한 postItem api를 받아 mutation을 적용해보자.

1
2
3
4
5
6
const mutation = useMutation((data: PutBodyProps) => postItem(data), {
onSuccess: () => {
queryClient.invalidateQueries('items');
},
});

먼저 전달할 인자를 postItem 에 알맞게 전달하고, onSuccessqueryClient 를 통해 이전에 정의해놓은 query key 값을 전달하여 데이터를 mutate 시킨다.