TanStack Query
는 서버 상태를 관리하고 비동기 데이터 페칭을 간편하게 할 수 있도록 도와주는 라이브러리다. React Query
로 시작했지만, 이제는 React
뿐만 아니라 다른 프레임워크에서도 사용할 수 있도록 확장되었다.
npm install @tanstack/react-query
자동 캐싱 및 동기화
: 데이터를 자동으로 캐싱하고, 필요할 때 자동으로 동기화한다.
백그라운드 데이터 업데이트
: 백그라운드에서 데이터를 자동으로 업데이트하여 최신 상태를 유지한다.
쿼리 무효화 및 재페칭
: 특정 조건이 충족되면 쿼리를 무효화하고 재페칭할 수 있다.
폴링 및 실시간 데이터
: 주기적으로 데이터를 페칭하거나 실시간 데이터를 처리할 수 있다.
오프라인 지원
: 오프라인 상태에서도 데이터를 관리할 수 있다.
개별 쿼리 관리
: 각 쿼리를 독립적으로 관리할 수 있다.
import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';
const queryClient = new QueryClient();
// App.jsx 또는 main.jsx
function App() {
return (
<QueryClientProvider client={queryClient}>
<MyComponent />
</QueryClientProvider>
);
}
App.jsx
또는 main.jsx
최상위 컴포넌트에 QueryClientProvide 로 감싼다.
// MyComponent
function MyComponent() {
const { isLoading, error, data } = useQuery(['todos'], fetchTodos);
if (isLoading) return 'Loading...';
if (error) return 'An error has occurred: ' + error.message;
return (
<div>
{data.map(todo => (
<p key={todo.id}>{todo.title}</p>
))}
</div>
);
}
//fetchTodos
async function fetchTodos() {
const response = await fetch('/api/todos');
return response.json();
}
fetchTodos
라는 서버에서 데이터를 가져오는 함수를 만들고 사용하는 컴포넌트에서 const { isLoading, error, data } = useQuery(['todos'], fetchTodos);
를 사용한다.
const { data, isLoading, error } = useQuery(
['posts', userId],
() => fetchPosts(userId),
{ enabled: !!userId }
);
React Query
의 useQuery
훅은 쿼리의 상태를 관리하는 여러 유용한 값들을 반환한다. 각 값은 현재 쿼리의 상태를 나타내거나 조작하는 데 사용된다.
data
queryFn
)가 반환한 데이터initialData
옵션)를 제공한 경우 초기값으로 설정undefined
const { data } = useQuery('posts', fetchPosts);
console.log(data); // 서버에서 가져온 데이터
isLoading
true
: 쿼리가 데이터를 가져오는 중.false
: 데이터 가져오기가 완료되었거나 실패한 경우true
const { isLoading } = useQuery('posts', fetchPosts);
if (isLoading) return <div>Loading...</div>;
error
null
: 에러가 발생하지 않은 경우null
const { error } = useQuery('posts', fetchPosts);
if (error) return <div>Error: {error.message}</div>;
isError
true
: 쿼리가 실패했음false
: 에러가 발생하지 않음false
const { isError } = useQuery('posts', fetchPosts);
if (isError) return <div>Something went wrong!</div>;
isFetching
true
: 데이터를 가져오는 중false
: 데이터를 가져오기가 완료되었거나 대기 상태isLoading
과 달리 쿼리가 초기 로딩 상태가 아닌 경우에도 데이터를 리패칭할 때 true
가 된다. const { isFetching } = useQuery('posts', fetchPosts);
if (isFetching) return <div>Fetching latest data...</div>;
status
"idel"
: 쿼리가 아직 실행되지 않음"loading
: 데이터를 가져오는 중"success"
: 데이터 가져오기 성공"error"
: 데이터 가져오기 실패 const { status } = useQuery('posts', fetchPosts);
if (status === 'loading') return <div>Loading...</div>;
if (status === 'error') return <div>Error occurred!</div>;
refetch
const { refetch } = useQuery('posts', fetchPosts);
const handleRefresh = () => {
refetch();
};
return <button onClick={handleRefresh}>Refresh Data</button>;
반환값 | 설명 | 초기 상태 |
---|---|---|
data | 쿼리 함수가 반환한 데이터 | undefined |
isLoading | 데이터 가져오는 중인지 여부 | true |
error | 실패 시 발생한 에러 객체 | null |
isError | 에러 발생 여부 | false |
isFetching | 데이터 가져오는 중인지 여부 | false |
status | 쿼리의 상태 (idle , loading , 등) | "idle" |
refetch | 데이터를 다시 가져오는 함수 | - |
- 첫 번째 인자 :
queryKey
(유니크한 키)
- 데이터 쿼리를 식별하기 위한 고유한 키이다.
- 타입 : string | unknown[]
- 역할 :
- React Query는 이 키를 기반으로 데이터를 캐싱하고 중복 요청을 방지한다.
- 배열 형태로 구체화된 키를 사용할 수 있으며, 배열의 요소는 동적으로 변경 가능하다.
- 예시 :
const { data } = useQuery(['posts', userId], fetchPosts);
// 'posts'는 데이터의 이름이고, userId는 특정 데이터를 식별하는 동적 요소입니다.
- 두 번째 인자 :
queryFn
(데이터를 가져오는 함수)
- 서버에서 데이터를 가져오는 함수이다.
- 타입 : (context: QueryFunctionContext) => Promise<TData>
- 역할 :
- 데이터를 비동기로 가져오며, React Query가 이 함수의 반환값을 캐싱한다.
- 함수 내부에서 queryKey를 사용할 수 있다.
- 예시 :
const fetchPosts = async (context) => {
const [_, userId] = context.queryKey; // queryKey로부터 userId 추출
const response = await fetch(`https://api.example.com/posts/${userId}`);
if (!response.ok) throw new Error('Failed to fetch posts');
return response.json();
};
const { data } = useQuery(['posts', userId], fetchPosts);
세 번째 인자 : options
(선택 사항)
UseQueryOptions<TData, TError, TQueryFnData>
enabled
:boolean
값으로 쿼리 실행 여부를 제어한다.true
이며, false
로 설정하면 쿼리가 자동으로 실행되지 않는다.userId
)가 유효할 때만 실행하도록 설정할 때 유용하다.const { data } = useQuery(
['posts', userId],
() => fetchPosts(userId),
{ enabled: !!userId } // userId가 유효할 때만 쿼리를 실행
);