A word of caution regarding React Concurrent Mode
The features described in this article are available for use, but you shouldn’t use them for professional development just yet. This new React mode has experimental features that will possibly change in the future. That said, React Concurrent Mode is currently available in the experimental build of React so, even though it is not yet available in the stable releases, you can still try out these new features by using the experimental builds.
What is concurrency?
Concurrency is a way to structure a program by breaking it into pieces that can then be executed independently. This is how you can break the boundaries of using a single thread and make your application more efficient.
So…what is React Concurrent Mode?
The React development Team defines React’s new mode as follows: “… Concurrent Mode is a set of new features that help React apps stay responsive and gracefully adjust to the user’s device capabilities and network speed.”
In other words, Concurrent Mode is a flag that allows React’s kernel to choose when to apply changes in the DOM when you are dealing with side effects, like Network requests. The main idea behind this is making React more intelligent.
A bit of history on React Concurrent Mode
When React’s kernel was completely rewritten on React Fiber, key features came in, like the ability to pause, abort, or reuse work as new updates come in, and the ability to assign priority to different types of updates.
However, the main benefit of the rewrite was the possibility of creating different virtual threads (called fibers) which are divided on different properties depending on whether the user is interacting or not with a component.
React Fiber laid the foundation on which Concurrent Mode works. Now, when some asynchronous event is tied to a component rendering, React can intelligently decide which elements of the virtual DOM have priority to be rendered.
An everyday example
Let’s imagine you have a single-page application that has a section where it must display a spinner, skeleton or placeholder while it is calling an API. Why is this necessary? Because this is a good indication that something is going on and, in this case, it buys you some time to show the returned data.
In “normal” React, you would see a spinner while React is finishing loading the layout, but it must reload the component to show the result that it got from calling the API’s endpoint.
It would be better if React waited a bit more to get a better performance and to show the user a final state of the user interface instead of intermediate states that are completely unnecessary and bothersome in the user experience.
Luckily for us, this is possible thanks to React Concurrent Mode. In more specific words, with Concurrent Mode the rendering process is broken down into smaller tasks, and a scheduler allows you to prioritize them based on importance. This then helps React:
- Not to block the main thread.
- To work on multiple tasks at a time and switch between them according to priority.
- To partially render a tree without committing the result.
- To make rendering interruptible and happen in multiple phases.
Let’s make a small application where you have to fetch a large number of images from an API; the idea is to show all the images once the data fetching is finished and that all images are rendered without intermediate states.
Assuming you have already created a React project (for example, using create-react-app), what you have to do next is enable Concurrent Mode on the index.js file of your application.
Here there’ll be a flag to change between React Concurrent Mode and “normal” React, so when your project is finished you will see the difference between the two modes.
Note: it is very important for the index.html file on your React project to have a div inside the <body> tag with a root ID. It should look something like this:
Next, you have to modify the react and react-dom versions in your package.json file to set the experimental build. Remember to run npm start or yarn start after making the changes.
Important note: both dependencies are constantly having new experimental releases. If you want to use the latest version instead of changing the package.json to a specific one, you can run one of the following commands.
- npm install react@experimental react-dom@experimental
- yarn add react@experimental react-dom@experimental
As you can see, in the package.json there is a react-bootstrap dependency. This is an easy way to include the spinner component that your application will use later. Once you have finished setting up your project, it is time to work with the App.js file and your custom components (ImageList.js).
Here there are a lot of new features. First of all, there’s the useTransition hook (imported and used as ‘’unstable_useTransition’). In this scenario, you have the images state that, while being fetched, causes the List Image component to suspend, so it must be updated using the useTransition hook.
This new hook returns two values:
- A function that takes a callback function in which you set the state.
- A boolean that lets you know when the transition is taking place.
The useTransition hook receives an argument that tells React how long to wait before suspending the component. That argument is the one you’ll be using to show the spinner.
This function will run the Fetch Images function. Then, whenever the promise is completed or rejected, it will change the status of the status variable. The read method will be used to get the images that will be displayed. When the promise is still pending, it throws the suspender variable, which contains your promise. When it gets rejected, it throws an error that is saved on the suspender variable. Finally, you return the result when the images have been fetched successfully.
You’ll start the transition with the useEffect hook and save the returned data in the useState hook. The <Suspense> component lets you “wait” for some code to load and declaratively specify a loading state—in this case, a spinner—while you are waiting.
Here you simply have a custom component to show all the images that you got from the API’s endpoint. It receives two props, which are the resources (the fetched images) and the pending state that is obtained from the useTransition hook; this last one is only used to change the CSS styles.
Here are some CSS Styles to make the final result look better. Now, you just need to test the application that you made and you should see how, after the spinner goes away, the rendering process feels smoother. If you go to the index.js file and change the boolean value to use “normal” React and run the application again (remember to clean cache), you will see how the rendering has decreased and feels heavier.
Last note: please remember that those experimental features are being constantly changed and this test application probably won’t work in the future. For example, the unstable_useTransition import and ReactDOM.unstable_createRoot() may change soon.
Final thoughts on react concurrent mode
This new mode is still in an experimental stage, but after its official release, it will bring many new possibilities and mark a before and after in React web application development and React Native mobile application development.
Before Concurrent Mode, React had no way of detecting that there were multiple dependencies to external services (like APIs), so it couldn’t do anything to improve the user experience. Now, with React Concurrent Mode, you can let React’s engine know about your dependencies with external services and let it use them in a smarter way, as well as make decisions about when to render the content. It is clear what those new React features are focusing on: it’s all about perfecting the User Experience.