Creating a fluidic user experience with concurrent rendering

Context:

In large-scale applications, the time taken to see the page and user experience plays a pivotal role at the frontend part. This time is referred to as the rendering time period.

There are many ways to reduce the render time like usage of SVG images, minifying the javascript files, avoiding imports etc. One such way which has been in a lot of limelight in the last 3–4 years is concurrent rendering which is still in the development phase.

Intro:

To make the concurrent mode understandable, we will use version control as a corollary. In a team, different people work on the same project but in different modules. So when one module is ready completely from one’s side he/she pushes the code in the repo and other team members take the pull to get the code. Similarly is the situation with concurrent mode. As the name suggests concurrent means side by side and so is the rendering process.

Description:

Concurrency is not a feature. It is a behind the scene mechanism which helps React to make multiple UI at the same time. It uses priority queues and multiple buffering which helps this process using the public API which is exposed. The legacy rendering method of React is non-interruptible i.e. once the rendering has started on a thread, it can’t be blocked in middle irrespective of any other process.

Image Credits: The Story of Concurrent React by uidotdev

In concurrent mode, the rendering is interruptible. That is if the user provides any input in the middle of rendering process, then the browser would halt the rendering at that point and take the input action as high priority and when completed would resume the rendering back creating a fluidic experience.

Image Credits: https://frontity.org/wp-content/uploads/2019/09/react-concurrent-mode.png

In the legacy React (17 & below) rendering, the UI would be showing a loader or some blank screen until the new DOM tree is completely created and ready to be rendered.

React 17 UI

Github Code React 17: https://dev.to/tmns/creating-better-user-experiences-with-react-18-suspense-and-transitions-3oje)

Here when the user switches to another tab the call tab switch is done first and then the data fetching and DOM updates are done. In the meantime, a fallback UI is seen which acts as compensation for the delay.

In React 18, with the introduction of concurrent mode, we can see the new DOM only when it gets completely made, then only it gets rendered. Here we have added a delay to show the use case for concurrent render( Reference : https://dev.to/tmns/creating-better-user-experiences-with-react-18-suspense-and-transitions-3oje)

React 18 UI

Github Code React 17: https://dev.to/tmns/creating-better-user-experiences-with-react-18-suspense-and-transitions-3oje)

Steps to change legacy code to React 18 code:

  1. Change

ReactDOM.render(<App />, document.getElementById(“root”));

to

const root = ReactDOM.createRoot(document.getElementById(“root”));

root.render(<App />);

2. Introduce useTransition hook i.e.

const [isPending, startTransition] = useTransition();

And use the startTransition function on the tab change as below

Change of handleClick function in React 17 (left) to React 18 (right)

Suspense in React 18

It is a component of React that is used to wrap other components that might take asynchronous requests. In React 16 and 17 it is referred to as legacy suspense while in React 18 it is termed as concurrent suspense. In legacy suspense, the components DOM node will be created immediately irrespective of the data fetched. While in concurrent suspense, the components will point to null until the above components get resolved and the suspense boundary is unblocked.

For example, in React 16 & 17 Component1 & Component2 will point to a specific DOM node irrespective of the data fetched while in React 18 it will point to null and Component2 will not get rendered until Component1 is resolved and ready to get rendered as well as the suspense boundary is unblocked i.e. fallback component is removed.

useTransition

The useTransistion is a hook that helps us to update the state without blocking the UI. It returns an array with two items, isPending flag which lets us know if the UI is in a pending transition state, and startTransition function which helps us update the state as a transition. This hook actually smoothens the UI tab switch as it takes the state update as a transition and so switches the tab only when the next component is ready to get rendered.

Overall React 18 gives us the advantage of having a custom fluidic UI which helps gives us the advantage over legacy React 17 & 16. Also, this gives a user a better experience in UI and a seamless single page application with enhanced performance.

In upcoming articles will be discussing more use cases and advantages of React 18 like automatic batching, useDefferedValue hook etc. Stay tuned for the same!

Creating a fluidic user experience with concurrent rendering was originally published in Walmart Global Tech Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.

Article Link: Creating a fluidic user experience with concurrent rendering | by Shantanu Bharadwaj | Walmart Global Tech Blog | May, 2023 | Medium