Suspense Boundaries
Suspense boundaries provide a declarative way to handle loading states in your application. Instead of manually checking if data is ready in each component, you can throw loading states up to parent components that know how to handle them.What is Suspense?
Suspense allows components to “suspend” rendering while waiting for asynchronous data. When a component suspends, the nearestSuspenseBoundary catches it and renders a fallback UI until the data is ready.
Basic Usage
The .suspend() Method
The key to suspense is the .suspend() method on resources. It does two things:
- If the resource is ready - Returns the value
- If the resource is pending - Throws a suspension error that bubbles up to the nearest
SuspenseBoundary
Suspense Boundary Props
Fallback
Thefallback prop receives a SuspenseContext and returns the UI to show while suspended:
Children
Any children under aSuspenseBoundary can suspend:
Combining with Error Boundaries
For robust error handling, combineSuspenseBoundary with ErrorBoundary:
ErrorBoundarywrapsSuspenseBoundaryto catch errorsSuspenseBoundarycatches loading states- Children can throw either errors or suspensions
Practical Example: Dog Photo Fetcher
Nested Suspense Boundaries
You can nest suspense boundaries for granular loading states:SuspenseContext API
TheSuspenseContext passed to the fallback provides useful information:
Methods
suspended_futures()- List of all suspended futuresis_suspended()- Whether the boundary is currently showing fallbackhas_suspended_tasks()- Whether there are any suspended tasksafter_suspense_resolved()- Run a callback when suspense resolves
Server-Side Rendering with Suspense
Suspense works seamlessly with SSR:On the Server:
- Initial render with loading placeholders
- Poll suspended futures
- Stream completed components to the client as they resolve
On the Client:
- Hydrate with initial placeholders
- Receive streamed updates from server
- Replace placeholders with real content
Advanced: Freezing Suspense
On the server, you can freeze a suspense boundary to prevent re-renders:Suspense Best Practices
1. Granular Boundaries
Use multiple small boundaries instead of one large one:2. Informative Fallbacks
Provide context in your loading states:3. Combine with Error Boundaries
Always wrap suspense with error boundaries:4. Non-Stateful Fallbacks
Keep fallback UI simple and stateless for SSR compatibility:Common Patterns
Progressive Loading
Show basic content first, then details:Skeleton Screens
Use skeleton components as fallbacks:Debugging Suspense
If your suspense isn’t working:- Check
.suspend()calls - Make sure you’re calling.suspend()on resources - Verify boundary placement - Ensure
SuspenseBoundaryis an ancestor - Check error boundaries - Errors might be caught before suspension
- Inspect context - Use the
SuspenseContextto debug state
Next Steps
- Learn about Error Handling for robust apps
- Understand use_resource for data fetching
- See Futures for background tasks