React concurrent mode has brought about a major shift in how we think about rendering user interfaces. It allows us to write more responsive and efficient applications by enabling us to break down work into smaller, concurrent tasks. One feature that goes hand in hand with concurrent mode is suspense, which allows us to gracefully handle loading states and error states in our components.
In this blog post, we will explore how we can combine suspense with React concurrent mode to create a smooth and engaging user experience.
What is suspense?
Suspense is a new feature introduced in React 16.6 that allows components to “suspend” rendering while waiting for some data to load. It provides a way to define loading and error states in our components, improving the overall user experience.
Enabling concurrent mode
To enable concurrent mode in a React application, we need to be using React version 16.6 or higher. Once we have the appropriate version, we can wrap our main component with the React.unstable_ConcurrentMode
component.
import React from 'react';
function App() {
return (
<React.unstable_ConcurrentMode>
{/* Your application components */}
</React.unstable_ConcurrentMode>
);
}
export default App;
Using suspense
Once we have enabled concurrent mode in our application, we can start using suspense to handle loading and error states. Suspense works by wrapping components that might need to wait for some data with a React.Suspense
component. The React.Suspense
component takes a fallback
prop, which is the component that will be rendered while waiting for the data to load.
Let’s look at an example:
import React, { Suspense } from 'react';
const LazyComponent = React.lazy(() => import('./LazyComponent'));
function App() {
return (
<React.unstable_ConcurrentMode>
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
</React.unstable_ConcurrentMode>
);
}
export default App;
In the example above, the LazyComponent
is being imported lazily using React’s lazy
function. The Suspense
component wraps the LazyComponent
and provides a fallback message to display while the component is loading.
Error boundaries
In addition to handling loading states, suspense also allows us to handle error states in our components. We can use error boundaries to catch and handle errors that occur during rendering. We can define an error boundary by creating a component that implements a componentDidCatch
method.
Here’s an example:
import React, { Component } from 'react';
class ErrorBoundary extends Component {
state = {
hasError: false,
};
componentDidCatch(error, info) {
// Log the error or show a custom error message
console.error(error);
this.setState({ hasError: true });
}
render() {
if (this.state.hasError) {
return <div>Oops! Something went wrong.</div>;
}
return this.props.children;
}
}
export default ErrorBoundary;
We can then wrap our components with the ErrorBoundary
component to catch any errors that occur during rendering:
import React, { Suspense } from 'react';
import ErrorBoundary from './ErrorBoundary';
const LazyComponent = React.lazy(() => import('./LazyComponent'));
function App() {
return (
<React.unstable_ConcurrentMode>
<ErrorBoundary>
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
</ErrorBoundary>
</React.unstable_ConcurrentMode>
);
}
export default App;
Conclusion
By combining suspense with React concurrent mode, we can create more responsive and efficient applications. Suspense allows us to handle loading and error states gracefully, providing a smoother user experience. Give it a try in your React applications and see the difference it can make.
#references {“React”: “https://reactjs.org/”, “concurrent mode”: “https://reactjs.org/docs/concurrent-mode-intro.html”}