무엇
useSuspenseQueries는 여러 쿼리를 한 번에 부르는 useQueries의 Suspense 판이다. 모든 쿼리를 병렬로 실행하고, 다 준비될 때까지 컴포넌트를 멈춘다.
개수가 바뀔 수 있는 쿼리 묶음을 다룰 때 쓴다. useSuspenseQuery는 훅이라 반복문·조건문 안에서 못 부르지만, 이 훅은 배열로 넘기므로 동적인 개수도 된다.
무슨 일이 일어나나
queries 배열의 항목마다 쿼리를 하나씩 만들어 병렬로 실행한다. 전부 끝날 때까지 컴포넌트는 멈춰 있다가, 다 되면 한꺼번에 렌더된다. 반환은 각 쿼리 결과의 배열이고, 항목마다 data는 반드시 정의돼 있으며 status는 success나 error만 나온다. isPlaceholderData는 없다. 각 항목에서 쓸 수 없는 옵션도 useSuspenseQuery와 같다 — suspense, throwOnError, enabled, placeholderData.
사용법
options에 queries 배열을 넘긴다. 각 항목은 useSuspenseQuery에 주던 옵션과 같다. 반환 배열은 순서가 그대로 보존되므로 구조 분해로 받을 수 있다.
import { useSuspenseQueries } from '@tanstack/react-query'
export function UserBundle({ id }: { id: string }) {
const [profile, posts] = useSuspenseQueries({
queries: [
{ queryKey: ['profile', id], queryFn: () => fetchProfile(id) },
{ queryKey: ['posts', id], queryFn: () => fetchPosts(id) },
],
})
// 둘 다 data가 보장된다
return (
<>
<h2>{profile.data.name}</h2>
<p>글 {posts.data.length}개</p>
</>
)
}
실무 예시
목록 하나로 개수가 정해지는 쿼리 묶음이다. 선택된 상품 id들의 상세를 한꺼번에 불러오는 경우, id 배열을 map으로 옮겨 그대로 queries에 넣는다.
import { useSuspenseQueries } from '@tanstack/react-query'
export function SelectedProducts({ ids }: { ids: string[] }) {
const results = useSuspenseQueries({
queries: ids.map((id) => ({
queryKey: ['product', id],
queryFn: () => fetchProduct(id),
})),
})
return (
<ul>
{results.map((r) => (
<li key={r.data.id}>{r.data.name}</li>
))}
</ul>
)
}
왜 중요한가
Suspense 환경에서 개수가 유동적인 쿼리 묶음을 다뤄야 할 때가 이 훅의 자리다. 쿼리 수가 고정이면 useSuspenseQuery를 여러 번 부르는 편이 더 단순하고, Suspense를 안 쓰면 아예 대상이 아니다. 쓰임이 좁은 만큼 자주 만나지는 않지만, 동적 배열과 Suspense가 겹치는 조합에선 이 훅 말고는 방법이 마땅치 않다.
Reference