React Query(리액트 쿼리) - Parallel Queries, Dependent Queries
iskkiri • 2024년 09월 22일
이번 글에서는 React Query의 Parallel Queries와 Dependent Queries에 대해서 알아보겠습니다.
코드와 예제 결과는 Codesandbox에서 직접 확인할 수 있습니다.
Parallel Queries
React Query에서 병렬로 여러 개의 데이터를 동시에 가져오는 기능은 Parallel Queries를 통해 구현할 수 있습니다. 병렬 쿼리는 두 가지 방식으로 처리할 수 있습니다.
- Manual Parallel Queries
Dynamic Parallel Queries
각각의 방법에 대해 살펴보겠습니다.
Manual Parallel Queries
Manual Parallel Queries는 고정된 개수의 쿼리를 병렬로 처리할 때 사용됩니다. 이 경우, 여러 개의 useQuery 훅을 나란히 작성하여 각 쿼리가 독립적으로 병렬로 동작하도록 합니다.
export default function ParallelQueriesPage() {
// manual-parallel-queries
const { data: post1 } = useQuery({
queryKey: ["POSTS", { id: 1 }],
queryFn: () => getPostDetailApi(1),
});
const { data: post2 } = useQuery({
queryKey: ["POSTS", { id: 2 }],
queryFn: () => getPostDetailApi(2),
});
const { data: post3 } = useQuery({
queryKey: ["POSTS", { id: 3 }],
queryFn: () => getPostDetailApi(3),
});
.
.
.
}
- Manual Parallel Queries는 쿼리의 개수가 고정적일 때 유용합니다. 여러 useQuery 훅을 나란히 사용하면 각 쿼리가 병렬로 데이터를 가져옵니다.
- 하지만 쿼리의 개수가 동적으로 변할 수 있는 경우에는 이 방법을 사용할 수 없습니다. 이는 훅의 규칙에 위반되기 때문입니다. 즉, 훅은 조건문 안에서 호출되거나 반복적으로 호출될 수 없기 때문에 쿼리 개수가 변경되면 수동으로 useQuery를 여러 번 호출하는 방식은 적합하지 않습니다.
Dynamic Parallel Queries With useQueries
Dynamic Parallel Queries는 쿼리의 개수가 매번 변하는 경우, useQueries 훅을 사용해 동적으로 쿼리를 병렬로 처리할 수 있습니다. 여러 개의 쿼리를 배열 형태로 관리하며, 동적으로 변화하는 쿼리의 개수에 대응할 수 있습니다.
export default function ParallelQueriesPage() {
// dynamic-parallel-queries-with-usequeries
// postIds가 prop으로 받고, 동적으로 길이가 변화될 수 있는 배열이라고 가정합니다.
const postIds = [1, 2, 3];
const [{ data: post1 }, { data: post2 }, { data: post3 }] = useQueries({
queries: postIds.map((id) => ({
queryKey: ['POSTS', { id }],
queryFn: () => getPostDetailApi(id),
})),
});
.
.
.
}
- useQueries는 배열로 쿼리 객체들을 받아들이며, 각 쿼리는 개별적으로 처리됩니다.
- 이 방법은 쿼리의 개수가 렌더링할 때마다 변화할 수 있는 경우 적합합니다.
- 결과적으로 useQueries는 쿼리의 결과 배열을 반환하며, 각 쿼리는 독립적으로 상태(로딩, 성공, 실패)를 관리합니다.
그러면 언제 useQueries를 사용할까? 🤔
React Query에서 Parallel Queries는 고정된 쿼리 수일 때는 Manual Parallel Queries 방식을, 쿼리 개수가 변할 가능성이 있을 때는 useQueries를 사용하는 것이 좋습니다. 쿼리의 개수가 변할 때는 훅의 규칙을 위반하지 않기 위해 수동 방식 대신 동적 방식인 useQueries를 사용하는 것이 필수적입니다.
Dependent Queries
Dependent Queries는 이전 쿼리가 완료된 후에 조건에 따라 실행되는 쿼리입니다. 이 방식은 연속적인(Serial) 데이터 페칭을 위해 유용하게 사용되며, 하나의 쿼리 결과에 의존하여 다음 쿼리가 실행됩니다.
예를 들어, 게시물 정보를 가져온 후 그 게시물의 작성자 정보를 가져오는 시나리오에서 Dependent Query를 사용할 수 있습니다. 이때 React Query의 enabled 옵션을 사용하여 특정 조건이 만족되었을 때만 쿼리가 실행되도록 할 수 있습니다.
Dependent Queries에서 코드와 예제 결과를 직접 확인할 수 있습니다.
예제 코드를 실행해보면 게시글을 가져오고, 1초 후에 유저에 대한 정보를 가져오는 것을 확인할 수 있습니다.
export default function DependentQueryPage() {
// 첫 번째 쿼리: 게시물 정보를 가져옴
const { data: post } = useQuery({
queryKey: ["POSTS", { id: 1 }],
queryFn: async () => {
await new Promise((resolve) => setTimeout(resolve, 1000));
return getPostDetailApi(1);
},
});
// 두 번째 쿼리: 게시물 작성자의 정보를 가져옴 (post가 존재할 때만 실행)
const { data: user } = useQuery({
queryKey: ["USER", { id: post?.user.id }],
queryFn: async () => {
await new Promise((resolve) => setTimeout(resolve, 1000));
return getUserApi(post?.user.id ?? 0);
},
// post 데이터가 로드된 후에만 이 쿼리가 실행됨
enabled: !!post?.user.id,
});
.
.
.
}
- 첫 번째 쿼리
- queryKey: ["POSTS", { id: 1 }]는 특정 ID를 가진 게시물 데이터를 가져옵니다.
- queryKey: ["POSTS", { id: 1 }]는 특정 ID를 가진 게시물 데이터를 가져옵니다.
- 두 번째 쿼리
- 두 번째 쿼리는 게시물 정보에서 받아온 작성자 ID에 의존합니다. 즉, post가 존재하고, post.user.id가 유효한 경우에만 실행됩니다.
- 이때 enabled 옵션이 중요한 역할을 합니다. enabled: !!post?.user.id는 post.user.id가 존재할 때만 이 쿼리를 실행하도록 조건을 설정합니다.
- 만약 첫 번째 쿼리가 아직 완료되지 않았다면, 두 번째 쿼리는 대기 상태에 있다가 첫 번째 쿼리가 완료되면 실행됩니다.
React Query에서의 enabled 옵션
- enabled 옵션은 쿼리가 실행될 조건을 설정할 수 있는 유용한 기능입니다. 기본값은 true이지만, 특정 조건이 만족할 때만 쿼리를 실행하고 싶다면 이를 false로 설정해 쿼리의 실행을 지연시킬 수 있습니다.
- 이 옵션은 의존 관계가 있는 쿼리에서 특히 유용합니다. 첫 번째 쿼리가 완료되지 않으면 두 번째 쿼리를 실행할 수 없는 시나리오에서, enabled를 사용하여 데이터 종속성을 관리할 수 있습니다.