기본적으로 쿼리들은 4개의 상태를 가지며, useQuery가 반환하는 객체의 프로퍼티로 상태를 확인할 수 있다.
[ 데이터 리패칭이 일어나는 경우 ]
- stale인 특정 쿼리 인스턴스가 다시 만들어졌을 때
- Window에 다시 포커스가 되었을 때 (쿼리 옵션)
- 네트워크가 다시 연결되었을 때 (쿼리 옵션)
- reFetch interval이 있을 때
요청 실패한 쿼리는 기본적으로 3번 더 요청하며, 이는 retry, retryDelay 옵션으로 커스텀이 가능하다.
여러 개의 쿼리를 다룰 때 사용한다. useQuery를 여러 번 사용해도 동작하지만 useQuries를 사용하자
[예시]
const getPost = async (query) => {
// useQuery의 queryKey 사용
const { data } = await axios.get(
`http://localhost:5000/posts/${query.queryKey[1]}`
);
return data;
};
const Parallel = () => {
// useQuery(["post", 1], getPost);
// useQuery(["post", 2], getPost);
// useQuery(["post", 3], getPost);
useQueries([
{ queryKey: ["post", 1], queryFn: getPost },
{ queryKey: ["post", 2], queryFn: getPost },
{ queryKey: ["post", 3], queryFn: getPost },
]);
return <div>Parallel Queries Page</div>;
};
[결과]
기본적으로 쿼리들은 순서가 보장되지 않는 비동기 방식으로 동작한다. 다른 쿼리에 의존해 순서가 보장되는 동기 방식으로 실행하려면 enabled 옵션을 사용하면 된다.
const getPost = async ({queryKey}) => {
const { data } = await axios.get(
`http://localhost:5000/posts/${queryKey[1]}`
);
return data;
};
const getUser = async ({queryKey}) => {
const { data } = await axios.get(
`http://localhost:5000/users/${queryKey[1]}`
);
return data;
};
const DependentQueriesPage = () => {
const { data: user } = useQuery(["user", "jae_han"], getUser);
const { data: post } = useQuery(["post", user?.postId], getPost, {
enabled: !!user?.postId,
});
console.log({ user });
console.log({ post });
return <div>Dependent Queries Page</div>;
};
[결과]
1. getUser 쿼리가 먼저 실행된다.
2. user 객체에 postId가 있는 경우에만 getPost 쿼리가 실행된다.
3. 이처럼 순서를 보장해 동기적으로 요청을 처리할 수 있다.
React Query는 기본적으로 5분동안 query key를 식별자로 가지면서 각 데이터들을 캐싱해 놓는다.
캐싱된 데이터를 사용함으로써 사용자 경험을 높일 수 있다.
[예시]
상세 페이지 이동 시 보여지는 데이터를 전체 조회에서 캐싱된 데이터를 사용한다.
//index.js
const getPosts = async () => {
const { data } = await axios.get("http://localhost:5000/posts");
return data;
};
export default function Home() {
const {
data: posts,
isLoading,
} = useQuery("posts", getPosts);
return (
<>
<div>
{isLoading ? (
<div>Loading...</div>
) : (
posts?.map((post) => (
<Fragment key={post.id}>
<br />
<Link href={`/post/${post.id}`}>
<a>
<div>id: {post.id}</div>
<div>제목: {post.title}</div>
<div>작성자: {post.author}</div>
<div>내용: {post.description.slice(0, 100)}...</div>
</a>
</Link>
<br />
<hr />
</Fragment>
))
)}
</div>
</>
)
}
메인 화면에서 useQuery("posts", getPosts) 를 통해 게시물 목록을 조회하고 5분동안 데이터를 캐싱시킨다.
// [id].js
const getPost = async (query) => {
const { data } = await axios.get(
`http://localhost:5000/posts/${query.queryKey[1]}`
);
return data;
};
const PostPage = () => {
const router = useRouter();
const { id: postId } = router.query;
const queryClient = useQueryClient();
const { data: post, isLoading } = useQuery(["post", postId], getPost ,
{
initialData: () => {
// 캐시 데이터로 초기화
const posts = queryClient.getQueryData("posts");
const post = postId ? posts?.find((post) => post.id === +postId) : null;
if (!post) {
return undefined;
}
return post;
},
}
);
return (
<div>
{isLoading ? (
<div>Loading...</div>
) : post ? (
<>
<div>id: {post.id}</div>
<div>제목: {post.title}</div>
<div>작성자: {post.author}</div>
<div>내용: {post.description}</div>
</>
) : null}
</div>
);
};
[결과]
참고
https://maxkim-j.github.io/posts/react-query-preview/
https://devkkiri.com/post/6783e9be-280a-469d-b377-dac40e7b214f