코드 출처 : https://github.com/Cluster-Taek/next14-boilerplate
user.ts
import { fetchApi } from './base';
import { IPageable } from '@/types/pageable';
import { IUser } from '@/types/user';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
export interface IUsersParams {
// paging params of json-server
_page: number;
_per_page: number;
}
export interface IUserCreateFormValue extends Record<string, unknown> {
name: string;
}
export const useUsers = (params: IUsersParams) => {
return useQuery<IPageable<IUser>>({
queryKey: [`/api/users`, params],
});
};
export const useCreateUserMutation = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (data: IUserCreateFormValue) => await fetchApi.post(`/api/users`, data),
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: ['/api/users'],
refetchType: 'all',
});
},
});
};
1. useQuery는 데이터 조회용
export const useUsers = (params: IUsersParams) => {
return useQuery<IPageable<IUser>>({
queryKey: [`/api/users`, params],
});
};
- useQuery는 데이터를 가져오는 용도로 사용됩니다.
- useQuery는 React Query에서 데이터를 캐시하고, 자동으로 갱신하며, 서버 상태를 관리하는 데 사용됩니다.
- 이 예제에서는 useQuery의 queryKey에 [/api/users, params]를 사용하여, 해당 쿼리가 이미 캐시된 데이터가 있으면 그것을 반환하고, 없다면 새로운 요청을 보내게 됩니다.
- 기본적으로 Axios나 fetchApi와 같은 API 호출 유틸리티를 사용하여 데이터를 가져오는 방식은 React Query 내부에서 자동으로 처리합니다.
- 즉, useQuery는 데이터를 가져올 때 API 호출을 내부에서 처리하며, 이 부분에서 fetchApi를 명시적으로 호출하지 않아도 되므로 fetchApi를 사용하지 않은 것입니다.
2. useMutation은 데이터 수정용
export const useCreateUserMutation = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (data: IUserCreateFormValue) => await fetchApi.post(`/api/users`, data),
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: ['/api/users'],
refetchType: 'all',
});
},
});
};
- useMutation은 데이터를 수정하거나 새로운 데이터를 생성할 때 사용됩니다.
- useMutation에서는 데이터를 서버에 전송하는 작업이므로, fetchApi를 사용하여 직접 POST 요청을 보내고 있습니다.
- mutationFn에서는 fetchApi.post를 호출하여 새로운 사용자를 생성하고, 이후 onSuccess에서 쿼리 무효화를 통해 캐시된 /api/users 데이터를 갱신합니다.
- useMutation은 데이터 수정 후 후속 작업을 처리하는 데 사용되므로, fetchApi와 같은 직접적인 API 호출 유틸리티를 사용합니다.
차이점:
- useQuery: 데이터를 읽고 가져오는 데 사용됩니다. 내부적으로 API 호출을 처리할 수 있지만, fetchApi를 명시적으로 사용할 필요는 없습니다.
- useMutation: 데이터를 생성, 수정, 삭제하는 데 사용됩니다. mutationFn을 통해 명시적으로 API 호출 유틸리티를 사용하여 서버와 상호작용합니다.
query-provider.ts
'use client';
import { fetchApi } from '@/lib/base';
import { getClearObject } from '@/utils/utils';
import { QueryClient, QueryClientProvider, keepPreviousData } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { useState } from 'react';
export const QueryProvider = ({ children }: { children: React.ReactNode }) => {
const fetcher = async (url: string, params?: Record<string, unknown>) => {
debugger;
return fetchApi.get(url, params);
};
const [queryClient] = useState(
() =>
new QueryClient({
defaultOptions: {
queries: {
retry: false,
staleTime: 1000 * 60,
gcTime: 1000 * 60 * 5,
queryFn: ({ queryKey }) =>
fetcher(queryKey[0] as string, queryKey[1] ? getClearObject(queryKey[1]) : undefined),
placeholderData: keepPreviousData,
},
},
})
);
return (
<QueryClientProvider client={queryClient}>
<ReactQueryDevtools />
{children}
</QueryClientProvider>
);
};
- React Query의 글로벌 queryFn을 QueryClient의 defaultOptions에서 설정하고 있습니다.
- 이 설정 덕분에 개별 useQuery에서 queryFn을 명시적으로 지정하지 않아도 전역적으로 정의된 queryFn이 실행됩니다.
queryKey에 /api/users가 들어가는 이유
- 코드에서 설정:
- useUsers 함수 내부에서 queryKey: ['/api/users', params]로 명시적으로 지정했기 때문에, queryKey[0]에 /api/users가 들어갑니다.
- fetcher 함수와 연결:
- QueryClient의 queryFn에서 이 queryKey를 받아, 첫 번째 요소(queryKey[0])를 URL로 사용하고 있습니다
동작 과정 요약
1.useQuery 호출
- React Query는 queryKey를 캐시의 키와 queryFn의 입력으로 사용합니다.
useQuery({ queryKey: ['/api/users', params], });
2.queryFn 실행
- 전역 queryFn에서 queryKey를 기반으로 데이터를 가져옵니다:
- 여기서 queryKey[0]이 /api/users로 전달되어 URL로 사용됩니다.
fetcher(queryKey[0], queryKey[1])
3. 결과 반환
- 데이터를 가져오면 React Query가 캐시를 업데이트하고, 컴포넌트는 그 데이터를 구독합니다.
'개발 공부 > React' 카테고리의 다른 글
| NextAuth.js 사용자 인증 로직 (1) (0) | 2025.01.11 |
|---|---|
| Next.js usePathname, useRouter, useSearchParams (0) | 2025.01.08 |
| Next.js 에서 모달 띄우기와 서버작업을 통한 유저 정보 받기 및 등록 (4) (0) | 2025.01.05 |
| Next.js 에서 모달 띄우기와 서버작업을 통한 유저 정보 받기 및 등록 (3) (1) | 2025.01.04 |
| Next.js 에서 모달 띄우기와 서버작업을 통한 유저 정보 받기 및 등록 (2) (0) | 2025.01.03 |