Capítulo 41 de 80
useSuspenseQuery/useSuspenseInfiniteQuery/useSuspenseQueries replace status/error handling with <Suspense> fallbacks and error boundaries, guaranteeing data is always defined at the type level — at the cost of losing per-query enabled toggling and placeholderData.
data is guaranteed non-undefined (loading/error states are handled entirely by <Suspense>/error boundaries), but queries can no longer be conditionally enabled/disabled per-instance, and placeholderData has no suspense equivalent — wrap query-key-changing updates in startTransition instead, to avoid the fallback flashing during a key change.throwOnError isn't "throw everything": only throws to the nearest error boundary when there's no data to show at all (typeof query.state.data === 'undefined') — a query that once succeeded keeps rendering its (possibly stale) data through a later error rather than unmounting into a boundary. This default can't be overridden (it would let data become undefined), but you can manually throw error from the component when error && !isFetching if you want stricter behavior.throwOnError: true to a useMutation if its errors should also propagate to the nearest error boundary, like suspense queries do by default.QueryErrorResetBoundary (component) or useQueryErrorResetBoundary (hook) resets a query's error state so the boundary's "try again" can actually re-attempt the query rather than immediately re-throwing the same cached error. The hook resets errors within the nearest QueryErrorResetBoundary, or globally if none is present.@tanstack/react-query-next-experimental's ReactQueryStreamedHydration lets useSuspenseQuery fetch server-side in a Client Component with results streamed to the client as Suspense boundaries resolve — no manual prefetch/dehydrate wiring needed, at the cost described in Advanced Server Rendering (client-navigation waterfalls aren't flattened the same way).const { data } = useSuspenseQuery({ queryKey, queryFn }) // data is never undefined
// Manually forcing all errors to the boundary, since throwOnError can't be overridden
const { data, error, isFetching } = useSuspenseQuery({ queryKey, queryFn })
if (error && !isFetching) throw error
// Resetting a boundary so "Try again" actually retries
<QueryErrorResetBoundary>
{({ reset }) => (
<ErrorBoundary onReset={reset} fallbackRender={({ resetErrorBoundary }) => (
<button onClick={resetErrorBoundary}>Try again</button>
)}>
<Page />
</ErrorBoundary>
)}
</QueryErrorResetBoundary>
data's guaranteed-defined shape under Suspense, manually escalating a stale-but-erroring query to the boundary, and wiring a resettable error boundary so retries work.QueryErrorResetBoundary/useQueryErrorResetBoundary — without it, "Try again" re-renders into the same cached error instead of retrying the query.enabled/placeholderData under suspense hooks — they don't apply there; restructure with conditional rendering or startTransition instead.useSuspenseQuery calls in one component run serially, not in parallel — use useSuspenseQueries (see Performance & Request Waterfalls) whenever more than one lives together.useSuspenseQueries fix.useSuspenseQuery on the server.