The Foundational Update to Core Rendering model React 18

kirill ibrahim
Geek Culture
Published in
10 min readMay 19, 2022

--

Introduction:

React 18 was released on March 8, 2022, with new updates, and improvements. The most important update is the Concurrent rendering model, It is a foundational update to React’s core rendering model, and most new features are built to take advantage of it. React 18 is just the beginning of what React team aims to build on this new foundation.

As we always expect from the React team significant improvements, and an easy guide to upgrade without the negative effects or expensive rewrite cost of our old projects.

Please follow me over Medium, to get a notification about next new articles. I’m also active on Twitter @IbraKirill.

We will explain in this article:

1-Concurrency Mechanism

2-New Features in React 18.

3-New Hooks in React 18.

4-Deprecations

5-React 18 Upgrade Guide

1-Concurrency Mechanism:

What is a concurrent Mechanism? It occurs when we are doing more than one thing at the same time. Not to be confused with parallelism, concurrency is when multiple sequences of operations are run in overlapping periods of time. They are operations that do not depend on each other.

Example 1: I have a phone call from a friend, while I am talking with him, My father calls me, I felt this may be an urgent call, so I told my friend that I will put him on hold, then answer my father’s call, after that switch to my friend’s call again.

Example 2: At morning I like to read book, then while I am reading book, I am cooking my spinash ommllet with tea, when the time comes to add ingredients, that will be urgent, i will leave book, focus on adding ingredients, when i am done, then continue reading book again. Meanwhile, my omlet is still cooking. I will focus on what is more urgent at various points during the reading and cooking process.

The concurrency doesn’t necessarily mean I talk to two people at once or cooking & reading at once, it is not a parallelism technique. It just means that at any moment, I may be on multiple calls or actions, and I choose who to talk to or which action I will make progress on it, based on which conversation or action is more urgent.

In previous versions of React, has an approach is called Blocking Rendering, updates are rendered in a single, uninterrupted, synchronous rendering so, It could only handle one task at a time. With synchronous rendering, once an update starts rendering, nothing can interrupt it until the user can see the result on the screen.

In React 18: Concurrent features are introduced, which makes rendering interruptible. The app may start rendering an update, pause in the middle, then continue later. React guarantees that the UI will appear consistent, even if a render is interrupted. To do this, it waits to perform DOM mutations until the end, once the entire tree has been evaluated. With this capability, React can prepare new screens in the background without blocking the main thread. This means the UI can respond immediately to user input even if it’s in the middle of a large rendering task, creating a fluid user experience.

Concurrent Mode in React is not a feature, but It is a foundational update to React’s core rendering model. It is a new behind-the-scenes mechanism that enables React to prepare multiple versions of your UI at the same time. You can think about concurrency as an implementation detail. It’s valuable because of the features that it unlocks. React uses sophisticated techniques in its internal implementation, like priority queues and multiple buffering. But you won’t see those concepts anywhere in our public APIs. So while it’s not super important to know how concurrency works, it may be worth knowing what it is at a high level.

So to apply concurrency on React, I put some of the following explanation from @sylwiavargas on Github:

Now, to translate the analogy, in React’s case “phone calls” are your setState calls. Previously, React could only work on one state update at a time. So all updates were "urgent": once you start re-rendering, you can't stop. But with startTransition, you can mark a non-urgent update as a transition.
You can think of “urgent” setState updates as similar to urgent phone calls (e.g. your father needs your help) while transitions are like relaxed conversations that can be put on hold or even interrupted if they're no longer relevant.

React team is planning to add a new component called <Offscreen> in an upcoming minor versions of React 18, you’ll be able to use Offscreen to prepare a new UI in the background so that it’s ready before the user reveals it, for example: when a user tabs away from a screen and back, React should be able to restore the previous screen in the same state it was in before.

As Andrew Clark said from React 18 KeyNote: “With React, designers and developers speak the same language.”

2-New Features in React 18:

A-Automatic Batching:

Before React 18, when we have groups of multiple state updates inside promises, setTimeout, native event handlers, or any other event, for example:

It will perform 3 re-renders for three state updates, of course, it is bad for performance.

React 18 is introduced automatic batching, React groups multiple state updates inside of promises, setTimeout, native event handlers, or any other event into a single re-render for better performance, so after upgrading to React 18, the above example will re-render one time only.

B- Suspense Feature:

Before React 18, when I am calling API to get data, the loading state will appear to the user in the shape of a spinner or any kind of UI loading component, when I am done with API, we will disappear spinner, & another component with data will appear.

Suspense makes the “UI loading state” a first-class declarative concept in the React programming model. Suspense lets you declaratively specify the loading state for a part of the component tree if it’s not yet ready to be displayed. It reduces the number of code lines, the code becomes clean code:

Suspense in React 18 works best when combined with the transition API. If you suspend during a transition, React will prevent already-visible content from being replaced by a fallback. Instead, React will delay the render until enough data has loaded to prevent a bad loading state.

Suspense on server:

Client-side rendering: the server renders a blank page with a script tag pointing at the app’s bundle. The blank page is sent to the client browser, which starts to run the app, compile everything, and then makes whatever API calls it needs to and renders the contents of the page.

If the JavaScript bundle is huge, or you have a slow connection, this process can take a long time and the user will be waiting for the page to become interactive, or to see meaningful content.

We can use the server rendering to make the user experience better and to prevent the user from sitting on a blank screen.

Server-Side Rendering: is the ability of an application to contribute by displaying the web-page on the server instead of rendering it in the browser. This means if you have an application that is server-side rendered, your content is fetched on the server-side and passed to your browser to display to your user. This lets the user view some UI while JS bundles are loading and before the app becomes interactive.

If most of the components in our app are fast except one or two of them, so One slow component can slow down the entire page, The rendering of this component was often the bottleneck in the app, increasing the rendering time.

Before React 18, we could not inform React to defer the loading of a slow component and could not inform React to send HTML for other components, until the loading of the slow component will be finished.

React 18 adds support for Suspense on the server. We can wrap a slow part of your app within the Suspense component, telling React to delay the loading of the slow component & specify a loading state that can be shown while it’s loading like a loading spinner, focusing on sending down the other, and when the slow component is ready and has fetched its data, the server renderer will pop in its HTML in the same stream.

The user can therefore see the skeleton of the page as soon as possible and watch it gradually reveal more content as the HTML arrives. Before any JS or React loads on the page, this is all done, resulting in an improved user experience and reduced perceived latency.

If you want to Dive into Server Side Rendering with React, I advise you with the following course.

C-Transitions:

Concurrency is when multiple sequences of operations are run in overlapping periods of time. Transition is introduced by React, it will help us with the concurrency mechanism, to distinguish between urgent and non-urgent updates.

Urgent updates need an immediate response for matching the user’s intuition and experience about how physical objects behave like typing, clicking, pressing, etc. For example, if there is a slight delay when the user clicks on a filter button for products, it is a bad experience for the user, because the user expects an immediate response, but If the user notices a slight delay in displaying the results of products after filtering, this small delay would be imperceptible and often expected.

Showing reflection on the clicked button to the user is important (immediate response) and therefore urgent. Showing the results of products after the filter is not so urgent, and so can be marked as non-urgent.

These non-urgent updates are called transitions. Transitions are different because the user doesn’t expect to see every intermediate value on the screen like urgent updates. By labeling non-urgent UI updates as “transitions”, React will know which updates to prioritize. Getting rid of stale rendering & optimize rendering becomes easier this way.

You can mark updates as non-urgent by using startTransition API. startTransition inform React which updates are urgent and which are “transitions”. Here is an example:

Updates wrapped in startTransition are handled as non-urgent and will be interrupted if more urgent updates like clicks or key presses come in. If a transition gets interrupted by the user (for example, by typing multiple characters in a row), React will throw out the stale rendering work that wasn’t finished and render only the latest update, so if you change the filter again before the results are done rendering, you only care to see the latest results.

D-New Strict Mode Behaviors:

React 18 introduced a huge breaking change, when in Strict Mode. all components mount and unmount, then mount again.

Before React 18:

After React 18, React will simulate unmounting and remounting the component in development mode:

React team is paving a way for new features that will be added to react in the future, like “Offscreen” API, to allow React to preserve a state like this by hiding components instead of unmounting them. For example, when a user tabs away from a screen and back, React should be able to immediately show the previous screen. To do this, React would unmount and remount trees using the same component state as before.

With Strict Mode in React 18, there is tricky behavior of useEffect hook:

3-New Hooks in React 18:

  • useId
  • useTransition
  • useInsertionEffect
  • useDefferedValue
  • useSyncExternalStore

I will gonna make a new article explaining these New Hooks.

4-Deprecations:

  • react-dom: ReactDOM.render has been deprecated. If we use it, our app will warn and run in React 17 mode.
  • react-dom: ReactDOM.hydrate has been deprecated. If we use it, our app will warn and run in React 17 mode.
  • react-dom: ReactDOM.unmountComponentAtNode has been deprecated.
  • react-dom: ReactDOM.renderSubtreeIntoContainer has been deprecated.
  • react-dom/server: ReactDOMServer.renderToNodeStream has been deprecated.

5-React 18 Upgrade Guide:

Great News: We will not change our entire code, or re-learn everything like what happened with Angularjs 1 to Angular 2+, we still write React code in the same way as before.

A-Install React 18 and React DOM from npm or yarn:

React 18 introduces a new root API that provides better ergonomics for managing roots. In index.js we should replace ReactDom.render to ReactDom.createRoot to create a root, and render your app using root.

React Team has also changed unmountComponentAtNode to root.unmount:

if React app uses server-side rendering with hydration, upgrade hydrate to hydrateRoot:

B-If React project uses TypeScript:

We will need to update @types/react and @types/react-dom dependencies to the latest versions. The new types are safer and catch issues that used to be ignored by the type checker. The most notable change is that the children prop now needs to be listed explicitly when defining props;

C-Adopting Concurrent Features:

We can use <StrictMode> to help surface concurrency-related bugs during development. Strict Mode doesn’t affect production behavior, but during development, it will log extra warnings and double-invoke functions that are expected to be idempotent. It won’t catch everything, but it’s effective at preventing the most common types of mistakes.

Conclusion:

This article covers most of the new things that React 18 has introduced. React team is paving the way to add many new features in the next versions of React.

I hope I added value, If you enjoy reading the article and want to support me as a writer, you can buy me a coffee!

If you want to Dive into React 18 with practical examples, I advise you with the following course.

If you want to Dive into Best Practices Patterns in React. I advise you with the following Course.

--

--

kirill ibrahim
Geek Culture

I am a Web Front-End Engineer with 8 years of commercial experience working in various web-related roles. https://kirillibrahim.work/ My Twitter: @IbraKirill