suspense
Description: If true, the useFetch hook will use suspense mode.
Default Value: true.
- How To: Prefer
suspense: truefor the primary data of a page or widget. This delegates loading UI to the nearest Suspense boundary, keeping your component code clean and promoting declarative loading states.// Correct: Leverage Suspense for main content loadinguseFetch('main-content',fetchMainContent); - Best Practice: Avoid setting
suspense: falseif you intend to useerrorBoundary: true, aserrorBoundaryrelies on Suspense to function. Ifsuspense: false, you must manually handleisLoadingstates within your component.// Avoid this: `errorBoundary` won't work without `suspense: true`useFetch('data',() => fetchData(),{ suspense: false, errorBoundary: true } // Won't work without suspense);
Deep Dive: How suspense works step by step
Example:
function UserList() {
const { data, isLoading } = useFetch('users', () => actionGetUsers(), {
suspense: true // Default
});
if (isLoading || !data) {
return null;
}
return <ul>{data.map(user => <li key={user.id}>{user.name}</li>)}</ul>;
}
<Suspense fallback={<LoadingSpinner />}>
<UserList />
</Suspense>
What happens step by step with suspense: true (default):
- Component renders →
useFetchis called - No cached data exists →
useFetchneeds to fetch useFetchthrows a Promise → This is the key behavior!- React Suspense catches the thrown Promise → Stops rendering
UserList <LoadingSpinner />is displayed → Fallback shows while waiting- Fetch completes → Promise resolves with data
- React re-renders
UserList→ Nowdatahas the users array - Component displays the list → No more Promise thrown
What happens step by step with suspense: false:
- Component renders →
useFetchis called - No cached data exists →
useFetchneeds to fetch useFetchreturns{ data: null, isLoading: true }→ No Promise thrown- Component continues rendering → Must handle
isLoadingmanually - You must check
isLoading→ Show your own loading UI - Fetch completes →
dataupdates,isLoadingbecomesfalse - Component re-renders → Now displays actual data
Key difference: With suspense: true, the Promise is thrown (error-like behavior), causing React Suspense to take over. With suspense: false, everything is returned as normal values.
The suspension seam (React 19 use())
Suspension is centralized behind a small seam so the mechanism can differ per hook:
useFetch(withsuspense: true) throws the pending, cache-stable promise — the classic React 18 style behavior.useSuspenseFetchunwraps the promise through the React 19use()API.use()suspends the render while the promise is pending, integrates with the nearest<Suspense>boundary, and re-throws a rejection to the nearest error boundary.
On runtimes that don't expose use() (older React, Preact), the seam falls back to throwing the promise, which suspends the same way. In both cases the promise must be referentially stable across renders — it comes from the data cache, not created inline — otherwise React would re-suspend forever.
If a component cannot render without its data, reach for useSuspenseFetch instead of useFetch with suspense: true. It forces suspense, errorBoundary and enabled on, guarantees an in-flight request even on a cold cache, and returns a non-null data.