React 애플리케이션에서 비동기 데이터를 관리하는 방법을 제공하는 라이브러리
캐시를 사용하여 데이터를 저장하므로 API에서 데이터를 한 번 가져온 다음 애플리케이션 전체에서 재사용가능
TenStack Query로 이름 변경됨
데이터를 가져오고 조회하는데 사용
import { useQuery } from 'react-query';
const { data, isLoading, isError } = useQuery('myData', fetchDataFunction); // 쿼리명, 쿼리함수, 옵션
useQuery에서 사용하고 싶은 기능들을 구조 분해 할당하여 사용
옵션
staleTime
cacheTime
쿼리키호출 => staleTime 안지났는지 확인 => 지났으면 서버에 호출 안지났으면 => 안지났으면 cacheTime 확인 => cacheTime 지났으면 가비지컬렉션이나 0이면 그냥 캐시가 없어서 아무튼 데이터없으니까 서버에 호출 => 안지났으면 (유효하면서) 데이터가 있는거니까 캐시데이터를 보여줌
컴포넌트를 다시 마운트하거나 윈도우를 다시 포커스할 때
useQuery에서 반환되어 수동으로 리페칭을 실행할 때
지정된 간격으로 리페칭을 자동 실행할 때
변이를 생성한 뒤 쿼리를 무효화 할 때
클라이언트의 데이터가 서버의 데이터와 불일치할 때 리페칭 할 경우
쿼리는 게시물 아이디를 포함하기 때문에 쿼리별로 캐시를 남길 수 있다.
각 쿼리에 해당하는 캐시를 가지게 된다.
각 게시물에 대한 쿼리에 라벨을 설정해주면 된다. 바로 쿼리 키에 문자열 대신 배열을 전달하면 가능하다.
const { data, isLoading, isError, error } = useQuery(
["comments", post.id], () => fetchComments(post.id)
);
이처럼 의존성 배열로 취급해서 사용하면 된다. comments를 쿼리키로 지정한 것이다.
그리고 post.id가 업데이트 되면 리액트쿼리가 새 쿼리를 만들고 staleTime과 cacheTime을 갖게 된다.
import { useQuery, 🌟useQueryClient } from "react-query";
const queryClient = useQueryClient();
useEffect(() => {
// 10페이지에 있다면 미리 데이터를 가져온 필요가 없다.
if (currentPage < maxPostPage) {
const nextPage = currentPage + 1;
queryClient.prefetchQuery(["posts", nextPage], () =>
fetchPosts(nextPage)
);
}
}, [currentPage, queryClient]);
const { data, isError, isLoading, error } = useQuery(
// 배열에 담긴 첫 번째 요소를 쿼리키라고 한다.
["posts", currentPage],
// 이 배열이 바뀌면 함수도 바뀌기 때문에 데이터가 바뀔 수밖에 없다.
() => fetchPosts(currentPage), // -> 함수의 파라미터값을 currentPage로 함
{
staleTime: 2000,
// 쿼리키가 바껴도 지난 데이터를 유지해서 이전 페이지로 돌아갔을 때 캐시에 해당 데이터가 있도록 해준다.
keepPreviousData: true,
}
);
데이터를 변경하거나 수정하기 위해 사용
import { useMutation } from 'react-query';
const mutation = useMutation(updateDataFunction);
const handleUpdate = () => {
mutation.mutate({ newData: 'newData' });
};
useMutation은 실제로, useQuery와 서로 다른 class 객체를 바라봄
useMutation은 쿼리키를 통해 데이터를 보관하지 않음 => 생성, 수정, 삭제 하기 위해서 api 요청을 하고 성공하면 refetch 또는 invalidateQueries를 통해 쿼리키의 데이터를 변경시켜줌
데이터가 변경될 때 캐시된 쿼리 결과를 무효화하여 새로운 데이터를 가져오도록 하는 메커니즘
데이터가 변경될 때 연관된 쿼리를 새로고침하거나 업데이트 가능
import { useQueryClient } from 'react-query';
const queryClient = useQueryClient();
const handleDataUpdate = () => {
// 데이터가 업데이트되면 'myData'라는 쿼리를 무효화하여 다시 요청합니다.
queryClient.invalidateQueries('myData');
};
import React from 'react';
import { useQuery, useMutation, QueryClient, QueryClientProvider } from 'react-query';
// API 호출 함수 정의 (가정)
const fetchData = async () => {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error('데이터를 가져오지 못했습니다.');
}
return response.json();
};
// React Query를 초기화하고 QueryClientProvider로 감싸기
const queryClient = new QueryClient();
function App() {
// 데이터 가져오기 쿼리
const { data, isLoading, isError } = useQuery('data', fetchData);
// 데이터 업데이트 뮤테이션
const mutation = useMutation(newData => {
// 서버에 데이터 업데이트 요청 (가정)
return fetch('https://api.example.com/update', {
method: 'POST',
body: JSON.stringify(newData),
});
});
const handleUpdate = () => {
// 데이터 업데이트 요청 보내기
mutation.mutateAsync({ someData: 'newData' });
};
if (isLoading) {
return <div>Loading...</div>;
}
if (isError) {
return <div>Error fetching data</div>;
}
return (
<div>
<h1>React Query Example</h1>
<button onClick={handleUpdate}>데이터 업데이트</button>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
function Main() {
return (
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
}
export default Main;
import React from 'react';
import axios from 'axios';
import {
useQuery,
useMutation,
QueryClient,
QueryClientProvider,
} from 'react-query';
// Axios를 사용하여 데이터 가져오기 함수 정의
const fetchData = async () => {
try {
const response = await axios.get('https://api.example.com/data');
return response.data;
} catch (error) {
throw new Error('데이터를 가져오지 못했습니다.');
}
};
// Axios를 사용하여 데이터 업데이트 함수 정의
const updateData = async (newData) => {
try {
const response = await axios.post('https://api.example.com/update', newData);
return response.data;
} catch (error) {
throw new Error('데이터 업데이트에 실패했습니다.');
}
};
// React Query를 초기화하고 QueryClientProvider로 감싸기
const queryClient = new QueryClient();
function App() {
// 데이터 가져오기 쿼리
const { data, isLoading, isError } = useQuery('data', fetchData);
// 데이터 업데이트 뮤테이션
const mutation = useMutation(updateData);
const handleUpdate = () => {
// 데이터 업데이트 요청 보내기
mutation.mutateAsync({ someData: 'newData' });
};
if (isLoading) {
return <div>Loading...</div>;
}
if (isError) {
return <div>Error fetching data</div>;
}
return (
<div>
<h1>React Query with Axios Example</h1>
<button onClick={handleUpdate}>데이터 업데이트</button>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
function Main() {
return (
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
}
export default Main;
https://tanstack.com/query/latest/docs/react/overview
https://velog.io/@leemember/React-query-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-useInfiniteQuery-%EB%A1%9C-%EB%AC%B4%ED%95%9C-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-react-infinite-scroller