How to Use Suspense with React Router for Lazy Loading
Use React's
Suspense component to wrap your Routes or lazy-loaded route components in React Router. This allows you to show a fallback UI while the route components load asynchronously using React.lazy().Syntax
Wrap your Routes or individual lazy-loaded components with Suspense. Use React.lazy() to import components lazily. Provide a fallback UI to show while loading.
React.lazy(() => import('./MyComponent')): Lazy loads the component.<Suspense fallback="<Loading />">...</Suspense>: Shows fallback UI during loading.<Routes><Route path="/" element="<LazyComponent />" /></Routes>: Defines routes with lazy components.
jsx
import React, { Suspense, lazy } from 'react'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; const Home = lazy(() => import('./Home')); const About = lazy(() => import('./About')); function App() { return ( <BrowserRouter> <Suspense fallback={<div>Loading...</div>}> <Routes> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> </Routes> </Suspense> </BrowserRouter> ); } export default App;
Output
When navigating to '/' or '/about', the app shows 'Loading...' briefly while the component loads, then renders the Home or About page content.
Example
This example shows a simple React Router setup with two lazy-loaded pages: Home and About. The Suspense component wraps the routes and displays a loading message while the pages load.
jsx
import React, { Suspense, lazy } from 'react'; import { createRoot } from 'react-dom/client'; import { BrowserRouter, Routes, Route, Link } from 'react-router-dom'; const Home = lazy(() => new Promise(resolve => { setTimeout(() => resolve(import('./Home')), 1500); // Simulate network delay })); const About = lazy(() => new Promise(resolve => { setTimeout(() => resolve(import('./About')), 1500); })); function Loading() { return <div>Loading page...</div>; } function App() { return ( <BrowserRouter> <nav> <Link to="/">Home</Link> | <Link to="/about">About</Link> </nav> <Suspense fallback={<Loading />}> <Routes> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> </Routes> </Suspense> </BrowserRouter> ); } const container = document.getElementById('root'); const root = createRoot(container); root.render(<App />);
Output
The app shows navigation links. Clicking Home or About shows 'Loading page...' for 1.5 seconds, then displays the page content.
Common Pitfalls
- Not wrapping lazy-loaded routes with
Suspensecauses errors because React needs a fallback UI. - Placing
Suspensetoo low or too high in the tree can cause unwanted loading states or block UI updates. - Using synchronous imports instead of
React.lazy()defeats the purpose of lazy loading. - Forgetting to handle loading states for nested routes can cause blank screens.
jsx
/* Wrong: No Suspense wrapper around lazy components */ import React, { lazy } from 'react'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; const Home = lazy(() => import('./Home')); function App() { return ( <BrowserRouter> <Routes> <Route path="/" element={<Home />} /> </Routes> </BrowserRouter> ); } export default App; /* Right: Wrap Routes with Suspense */ import React, { Suspense, lazy } from 'react'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; const Home = lazy(() => import('./Home')); function App() { return ( <BrowserRouter> <Suspense fallback={<div>Loading...</div>}> <Routes> <Route path="/" element={<Home />} /> </Routes> </Suspense> </BrowserRouter> ); } export default App;
Quick Reference
Tips for using Suspense with React Router:
- Always wrap lazy-loaded routes or components with
Suspense. - Use a meaningful
fallbackUI to improve user experience. - Lazy load only large or rarely used components to optimize performance.
- Consider nested
Suspensefor nested routes to show partial loading states. - Test loading states by throttling network speed in browser DevTools.
Key Takeaways
Wrap lazy-loaded route components with React's Suspense to handle loading states.
Use React.lazy() to import route components asynchronously for better performance.
Provide a fallback UI inside Suspense to show while components load.
Avoid missing Suspense wrappers to prevent runtime errors.
Test your loading UI by simulating slow network conditions.