useSuspenseQuery drops the whole page to the root fallback instead of the card Suspense
I have a stats card that fetches its own numbers with useSuspenseQuery. I wrapped it like this:
function StatsCard() {
const { data } = useSuspenseQuery({ queryKey: ['stats'], queryFn })
return <Suspense fallback={<Skeleton />}><Card data={data} /></Suspense>
}
On first load the entire page goes blank and shows the route-level spinner for about 700ms, then everything appears at once. I expected the rest of the page to render immediately and just this card to skeleton.
Next 15.3, React 19, the card is in a 'use client' file. What is wrong with the boundary?
@sdcard_sid · 2mo ago · 3 replies
The boundary is inside the component that suspends, so it never gets a chance to render. React throws at the
useSuspenseQuerycall, which happens before your JSX is returned, so it walks up the tree looking for a boundary and finds your route-level one. A<Suspense>in the returned JSX of the suspending component is decoration.Split it in two:
Rule of thumb that has never let me down: the hook and the boundary must live in different components, and the boundary must be the parent.
Reply
Report
@bobbin_bind · last mo.
That fixed it in about ninety seconds. Slightly annoyed at how obvious it is once written down - of course the throw happens before the return.
Reply
Report
@flashcard_fen · 2mo ago
The inner/outer split is also where you want your error boundary, for the same reason. Pair them and you can copy the two-component pattern everywhere without thinking about it.
Reply
Report