Combining suspense with React concurrent mode

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”}