React 18 – performance improvements

Nov 8, 2022by, Digina T D


In March 2022, React 18 was released. The most recent version includes a lot of new capabilities that will change the coding pattern in a variety of applications.


Concurrency is a feature that occurs when multiple processes are running at the same time and may or may not interact. Let’s have a look at it in more detail. Let’s pretend that there is a race going on. Now, concurrency refers to the number of persons competing in a single race on a parallel track.
Concurrency is a new feature added in React 18. It’s a new behind-the-scenes technology that allows React to simultaneously prepare various versions of the user interface.
Unlike in earlier versions, React may start rendering, pause in the midst for a necessary operation, and then restart rendering. The only thing to keep in mind is that it may stop rendering in the middle of the procedure.
Even if the render is interrupted, React ensures that the UI remains constant.
This allows React to prepare screens in the background without interfering with the new thread!

Suspense for Server Side Rendering

Suspense is a feature introduced by React in server-side rendering frameworks such as Next.js, Relay, Hydrogen, and Remix. Code splitting on the server with suspense and server-side streaming rendering are two new features in React 18.
Suspense is a feature introduced by React in server-side rendering frameworks such as Next.js, Relay, Hydrogen, and Remix. Code splitting on the server with suspense and server-side streaming rendering are two new features in React 18.

Automatic Batching

Batching is a speed optimization technique in which React bundles many state updates into a single re-render.
Batch updates were used for react-based event handlers prior to React 18. Batch updates were not performed for promises, setTimeouts, native event handlers, or any other events. For the instances stated above, React 18 also conducts automatic batch updates.

Let’s look at this through the lens of a code.


The above code acts in the same way as this:


If you don’t want to batch, use ReactDOM.flushSync() instead. Let’s break it down with some code.



This feature differentiates between urgent and non-urgent updates. An urgent update is one that requires rapid attention. Urgent updates are activities like clicking, pressing, and typing that demand a quick response or where the user expects the user interface to respond quickly.
On the screen, no intermediate values are to be displayed.

A real life example

Let’s consider a debounced typeahead as a real-life example. Now, as you type into the input box, you expect the values written to be reflected in the input box. Do you, on the other hand, expect the result to emerge right away? No! It will debounce, and you will receive a result. As a result, there is a period of delay between the time you type your input and the time you receive your suggestion. The transfer will take place within this time range.
A single user input should typically result in both urgent and non-urgent updates for the optimum user experience.


Another real-time example

The useTransition hook contains two destructured parameters in this case.
isPending: startTransition: if the UI update is still in transition

startTransition: if the UI update is still in transition start a function that runs transactional code.
Calling the useTransition hook returns an array with the first value being an isPending variable and the second value being the startTransition function. The isPending variable simply returns true while the code inside the startTransition hook is running. Essentially, this variable is true when the slow state update is running and false when it is finished running. The startTransition function takes a single callback and this callback just contains all the code related to the slow state update including the setting of the state.

function App() {
const [name, setName] = useState("")
const [list, setList] = useState(largeList)
const [isPending, startTransition] = useTransition()

function handleChange(e) {
startTransition(() => {
setList(largeList.filter(item =>

return <>
<input type="text" value={name} onChange={handleChange} />
{isPending ? (
) : ( => <ListComponent key={} item={item} />)

In our case we are wrapping setList in our startTransition function which tells React that our setList state update is of low importance. This means that as soon as all of our normal state updates are finished that the component should rerender even if this slow state update is not finished. Also, if a user interacts with your application, such as clicking a button or typing in an input, those interactions will take higher priority than the code in the startTransition function. This ensures that even if you have really slow code running it won’t block your user from interacting with the application.

Here is an example of what our list acts like with the useTransition hook.

Item: a
Item: a
Item: a
Item: a
Item: a

Using this hook is quite easy, but this is not something you want to use all the time. You should only use this hook if you are having performance issues with your code and there are no other ways to fix those performance concerns. If you use this hook all the time you will actually make your app less performant since React will not be able to effectively group your state updates and it will also add extra overhead to your application.
When you want to transition from the Photos tab to the Comments tab, this function is called.

During the transition period, while React prepares the new UI, the tab with the Photos UI will be visible to the user with an opacity of 80 percent to provide a smooth transition.

New Hooks

  • useId

useId is a new hook that allows you to generate** unique IDs on both the client and the server while preventing hydration mismatches. This creates a **one-of-a-kind string containing: that does not conflict with css selectors or querySelectorAll*.
In multi-root applications, you can also use userId with identifierPrefix to avoid collisions. Append a suffix using the same id to numerous IDs in the same component.

  • useDeferredValue

You can use useDeferredValue to postpone re-rendering a non-urgent part of the tree. Remember how we discussed non-urgent rendering? Because there is no set time delay, React will attempt the deferred render as soon as the initial render appears on the screen.

  • cuseSyncExternalStore

useSyncExternalStore is a new hook that forces synchronous updates to external stores, allowing them to enable concurrent reading. When creating subscriptions to external data sources, it eliminates the need for useEffect.
Code snippet:

  • useInsertionEffect

The useInsertionEffect hook helps CSS-in-JS libraries to address performance difficulties with injecting styles in render. This hook will be called after the DOM has been changed, but before the layout effects have had time to read the new layout. This hook will aid in layout calculation in tandem with concurrent re-rendering.


There are a few additional minor but major changes, such as using the createRoot() hook instead of ReactDOM.render. This method will be used to umount utilizing root and render a DOM element. unmount()
React also supports streaming suspense for servers that use renderToPipeableStream and renderToReadableStream.
In this published version, React developers continue to focus on enhancements and improvements, as well as a few bug fixes. The upgrade isn’t meticulous and may be completed in a single morning session. So, application developers, what are you waiting for? Let’s get our library up to date and get to work! Congratulations to the React team!If you have any projects regarding the above, contact us.

Disclaimer: The opinions expressed in this article are those of the author(s) and do not necessarily reflect the positions of Dexlock.

  • Share Facebook
  • Share Twitter
  • Share Linkedin