In React, Suspense
is a built-in component that helps in handling asynchronous loading states for components that are dynamically imported. When combined with React.lazy()
, it allows you to load components lazily, which means loading them only when they are needed, rather than loading them upfront. This can significantly improve the performance of your app by reducing the initial bundle size.
Steps to Use Suspense
for Code Splitting:
1. Install React (if you haven’t already)
Make sure you’re using a React project. If you need a new React project, you can create one with Create React App:
npx create-react-app my-app
cd my-app
npm start
2. Import React.lazy
and Suspense
To use code splitting, you need to import both React.lazy
and Suspense
from React.
import React, { lazy, Suspense } from 'react';
3. Lazy Load Components with React.lazy()
Use React.lazy()
to dynamically import your components. For example, if you have a Home
component that you want to load lazily, you would do something like this:
const Home = lazy(() => import('./Home'));
React.lazy()
takes a function that returns a dynamic import()
statement. This tells Webpack to split this component into a separate chunk.
4. Wrap Components with Suspense
Suspense
is a component that you wrap around your lazy-loaded components to provide a loading fallback (such as a loading spinner or message) while the component is being loaded.
function App() {
return (
<div>
<h1>Welcome to my React app!</h1>
<Suspense fallback={<div>Loading...</div>}>
<Home />
</Suspense>
</div>
);
}
- The
fallback
prop ofSuspense
specifies the UI to show while the component is loading. In this example, a simple loading message (<div>Loading...</div>
) is shown untilHome
is fully loaded.
5. Example with Multiple Lazy Loaded Components
You can use Suspense
to load multiple components lazily:
import React, { lazy, Suspense } from 'react';
const Home = lazy(() => import('./Home'));
const About = lazy(() => import('./About'));
function App() {
return (
<div>
<h1>React Lazy Loading with Suspense</h1>
<Suspense fallback={<div>Loading Home...</div>}>
<Home />
</Suspense>
<Suspense fallback={<div>Loading About...</div>}>
<About />
</Suspense>
</div>
);
}
export default App;
In this example:
- The
Home
component is lazily loaded, and while it’s loading, the text “Loading Home…” is shown. - Similarly, the
About
component is lazily loaded, and while it’s loading, the text “Loading About…” is shown.
6. React Router with Code Splitting
If you are using React Router, you can combine lazy loading with Suspense
to load routes on demand.
import React, { lazy, Suspense } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
function App() {
return (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
</Switch>
</Suspense>
</Router>
);
}
export default App;
In this case:
- The
Home
andAbout
components are loaded lazily when the user navigates to those routes. - The
Suspense
component wraps the entire route switch, so any lazily-loaded component will show the fallback content until it’s loaded.
7. Using Suspense
with Custom Fallbacks
You can provide a custom fallback UI. For example, you might want to show a spinner or a progress bar while the component is loading:
import React, { lazy, Suspense } from 'react';
import { CircularProgress } from '@material-ui/core';
const Home = lazy(() => import('./Home'));
function App() {
return (
<div>
<h1>Lazy Loading with Suspense</h1>
<Suspense fallback={<CircularProgress />}>
<Home />
</Suspense>
</div>
);
}
export default App;
Here, we’re using Material-UI’s CircularProgress
component to show a spinner while the Home
component is being loaded.
8. Error Boundaries with Suspense
While Suspense
handles loading states, it doesn’t catch errors that occur during the loading of components. To handle errors, you can use Error Boundaries in combination with Suspense
.
import React, { Component, lazy, Suspense } from 'react';
// Error Boundary
class ErrorBoundary extends Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
console.log("Error occurred:", error, info);
}
render() {
if (this.state.hasError) {
return <div>Something went wrong!</div>;
}
return this.props.children;
}
}
const Home = lazy(() => import('./Home'));
function App() {
return (
<div>
<h1>React Suspense with Error Boundaries</h1>
<ErrorBoundary>
<Suspense fallback={<div>Loading...</div>}>
<Home />
</Suspense>
</ErrorBoundary>
</div>
);
}
export default App;
Here, if there’s an error in loading the Home
component, the ErrorBoundary
will catch the error and display an error message.
9. Benefits of Using Suspense
for Code Splitting
- Improved Performance: Code-splitting with
Suspense
ensures that only the necessary parts of your app are loaded initially, making your app load faster. - Reduced Initial Bundle Size: With lazy loading, large components are split into smaller chunks, reducing the initial JavaScript payload.
- User Experience: By showing a fallback UI while waiting for a component to load, you can provide a smoother experience to your users, rather than them seeing a blank screen.