React Latest Version — Everything You Need To Know (React 18)

React Latest Version — Everything You Need To Know (React 18)

What’s new in React 18

The React community eagerly awaits each new version of the React library, which is the most commonly used web framework these days. In the last year, it has even overtaken jQuery, which has been the king of web libraries for many years, according to the latest Stack Overflow survey. It also earned the title of best UI framework and took the fourth position in the Most Popular Projects section in the JavaScript Rising Stars ranking by bestofjs

The preview version, 17, didn’t bring any new groundbreaking features, compared to other React versions. Instead, it focused on ensuring that updating goes as smoothly as possible in addition to improving the basics. We got a bug fix for a false positive warning when dangerouslySetInnerHTML is undefined (#18676), the unnecessary internals for React Native Web are no longer exposed (#18483), calling ReactDOM.flushSync during lifecycle methods became possible (#18759), and many others.

The expectations are extremely high for React latest version. The upcoming release is already in the release candidate stage, so let’s take a look at the fresh functionalities that will soon be introduced — like new APIs, concurrent mode, or enhanced server–side rendering.

Let’s see what awaits React developers.

Concurrent mode

React 18 adds many new features that use concurrent rendering under the hood. This new fantastic feature was announced about half a year ago, and now it’s in its second stage of support, which means it’s working, but still needs some improvements. Why is it important? Because it’s the core mechanism of many new features, like automatic batching, new Suspense API for side-server rendering, startTransition API, and more.

The biggest challenge in implementing concurrent mode is tearing — an inconsistency in the user interface which can happen due to multithreading. Because React handles many updates at once, you can witness two different values for the same data on the page. So, for example, if a user clicks quickly and several times on a UI element that affects the price (let it be a button that changes the value between net and gross price), they may see different versions. Why does it happen, exactly?

  1. The user clicks on the button,
  2. React starts the re–rendering process and renders the price component,
  3. The impatient user clicks on the button again,
  4. React pauses the rendering immediately to handle the new action in order to show off its responsiveness,
  5. The price changes and React goes back to handling the first rendering process,
  6. In result, the second component displaying the price of the product has the new value, while the first element displays the old one.

The example above illustrates the amount of work and all the problems that had to be solved to make concurrent mode stable and reliable. This is a major step forward setting the direction for web development for the near future.

useSyncExternalStore hook

It’s probably the most exciting change in the React library since the introduction of React Hooks. useSyncExternalStore hook is the result of long and hard work on useMutableSource, but the name had to be altered due to a complete change in the implementation approach in response to encountered problems. Once it will be deployed with React 18, the devs will no longer have to remember to memoize selectors related to the stores. Let’s take a look at this feature in action (source):

import {useSyncExternalStore} from 'react';

// We will also publish a backward-compatible shim
// It will prefer the native API, when available
import {useSyncExternalStore} from 'use-sync-external-store/shim';

// Basic usage. getSnapshot must return a cached/memoized result
const state = useSyncExternalStore(store.subscribe, store.getSnapshot);

// Selecting a specific field using an inline getSnapshot
const selectedField = useSyncExternalStore(store.subscribe, () => store.getSnapshot().selectedField);

A new Suspense Server-side rendering architecture

Server-side rendering (SSR) lets you generate HTML from React components on the server, and send that prepared HTML to the client. Once an HTML document is received by the browser, it connects with the JavaScript code in the process called hydration. So far this process was synchronous: 

  1. The server fetched data for the entire app,
  2. Rendered the HTML, 
  3. Sent the results to the browser,
  4. The browser connected it with the JS code for the entire app at once. 
Traditional server-side rendering illustrated. The process starts with the server processing a request and sending back HTML ready to be rendered. Then the browser renders HTML and downloads JS. Next, the browser hydrates the DOM. And lastly, the page starts to be interactable.
Server-side rendering using suspense in React latest version (18) illustrated. The process starts with the browser sending a request to the server. Then, browser downloads JS files and the server starts the process of preparing and streaming parts of HTML. So the server simultaneously prepares different parts of HTML, then sends those parts to the browser, and lastly, hydrates the DOM. Therefore each fragment of the HTML may be ready in a different time.

Since this process turned out to be inefficient, the new version of the library aimed to improve it. It will use the Suspense API to break down an application into smaller units which will go through the process described above independently. You can segment your page to render just the right components that load quickly and are urgent to the integrity of the whole page, and then wait for the slower ones. Now the users don’t have to wait for the entire app to be rendered and hydrated, but can see its parts as soon as they pass the process, without having to wait for the others. 

Additionally, the upcoming version of React implements one more functionality related to this — prioritized hydration. If the user clicks on any component’s fallback view, its hydration will get a higher priority. 

It is also worth noting that React.lazy feature also works with SSR now. This enables wrapping of slow components with Promise and giving fallback components which will be rendered faster. As a result, the entire page will be ready to interact with the user in no time, with the slower components added once they’re fully loaded. If you want to learn more, the official documentation describes it in a really accessible way.

startTransition API 

Do you know that feeling when you move the zoom slider and the entire page starts to throttle when the map is rerendered? Developers were trying to fix this by using setTimeout or debouncing. However, these techniques are just a prosthesis that reduces the amount of re-renders, but they are still done synchronously, so for a moment the application may be unresponsive. 

In React 18 it will become just an unpleasant memory thanks to the startTransition API. With this feature, you will make your user interfaces more friendly and responsive. It will also allow you to provide feedback quickly about the changed input to the user and begin rendering the modified view in the background between crucial UI changes. All you have to do is wrap your method which modifies the state with a startTransition(), as in the example below:

import { startTransition } from 'react';
// ...

function FastSlider({defaultValue, onChange}) {
  const [value, setValue] = useState(defaultValue);
  
  return (
    <Slider
      value={value}
      onChange={(e, nextValue) => {
        // Update the slider value.
        setValue(nextValue);
        
        // Call the onChange callback.
        onChange(nextValue);
      }}
    />
  );
}

function ClassicAssociationsBubbles({associations}) {
  const [minScore, setMinScore] = useState(0.1);
 
  const data = computeData(minScore);

  return (
    <>
      <FastSlider defaultValue={0.1} onChange={val => {
        // Update the results, in a transition.
        startTransition(() => {
          setMinScore(val);
        });
      }/>
      <ExpensiveChart data={data}/>
    </>
  );
}

Is it the only case where this feature will be helpful? Of course not. You can also use it for the search bar with dynamically fetched autocomplete suggestions. To do it, you have to split your UI into two pieces: 

  • the search input — a component whose changes are crucial to the user experience,
  • the autocomplete suggestions list — this component doesn’t have to be updated immediately, so as a developer you can wrap its changes with the startTransition.

The interface will be responsive and all functionality will work exactly as it should. You can forget about debouncing, setTimeout and other methods trying to mask the problem. It’s finally solved!

Automatic batching

Another brilliant solution coming in the next version of React is automatic batching —  the mechanics of combining multiple state updates together into a single re-render. It’s not really an entirely new feature, but a powerful update. 

Let’s take a look at the example:

const [count,setCount] = useState(0);
const [clicked, setClicked] = useState(false);

function handleClick() {
	setCount(count+1);
      setClicked(true);
}

If you call the handleClick function, the component will be rendered only once, although you might think setCount and setClicked would trigger two re-renders. If you follow the library changes closely, you may notice that it has been working this way for quite some time, but until now it has only worked in this particular context. 

React 18 will be able to batch the state updates even in promises, callbacks, and timeouts. That’s a big step forward! This will certainly have a positive impact on applications’ performance and memory usage.

Is it 100% safe to use, though? Is there any guarantee that your codebase won’t break? 
The React Team took that into consideration and prepared a possibility to opt out of the batching. If you don’t want to use it in some place in your application, you can simply wrap all the state updates with the flushSync() method, like in the example below:

import { flushSync } from 'react-dom'; // Note: react-dom, not react

function handleClick() {
    flushSync(() => {
        setCount(count + 1);
    })

    flushSync(() => {
        setClicked(true);
    })
}

Simple, isn’t it?

useId

This is another new feature that solves one of the common problems — generating the same unique IDs for both the client– and server–side. In the upcoming version of the library, this task becomes much more crucial due to the concurrent mode, which may cause more hydration mismatches between the server and the browser. useId will generate stable ids during server rendering and hydration to avoid those mismatches. If you want to know how the algorithm creates globally unique IDs, look here

The React Team also have made sure that using the new API will be intuitive — look at the example code:

function Checkbox() {
  const id = useId();
  return (
    <>
      <label htmlFor={id}>Do you like React?</label>
      <input type="checkbox" name="react" id={id} />
    </>
  );
);

Upgrading to React 18

A lot of new features, huh? Let’s check how much work you have to put into updating your existing app. Of course, the first step will be to update the library. At this time, React 18 can be installed using the following command: 

npm install react@rc react-dom@rc

Then you have to change all occurrences of the ReactDOM.render method to the new, ReactDOM.createRoot function to take advantage of these new features described above, especially those that use concurrency. 

Interestingly, if you neglect to do that, your app will still work, but you won’t be able to reap the benefits of the latest features. In most cases, the change will only be required in one place: the application’s main file. After this step, your file should contain something similar to this:

let container = document.getElementById('root');
let root = ReactDOM.createRoot(container);
root.render(<App />);

And that’s it! That should be enough to enjoy the new features.

Can this update break some libraries? Yes, but it should be a rare occurrence. If it happens to you, you can try to update those dependencies that prevent your app from working properly. Many libraries are already prepared for updates and have their early versions available in package manager repositories.

Libraries compatible with React 18

As of this writing (January 2022), many libraries have already released new versions that are ready to work with React 18.

  • Next already supports some features from the upcoming version of React, and they prepared a helpful set of tips on how to install and configure it properly. In this document you can also check the details of the current state – which features are working, which are partially implemented, and which are still waiting for their turn;
  • Gatsby, probably the most popular React-based framework, supports React 18 with its concurrent features starting with version 3.7. The note on their blog seems a bit outdated since it refers to version 3.7, while they have already released v4.5, so I guess it can be used with an upcoming version of React without much trouble;
  • Relay, the GraphQL client, has full support for the new React. That’s because the developers behind Relay were in close collaboration with the React team while developing React 18;
  • Apollo already uses the new useSyncExternalStore API to ensure compatibility with concurrent features;
  • React Redux, like Apollo, also uses the new feature to manage stores;
  • React Testing Library v13 (currently in alpha stage) will automatically switch your tests to createRoot, so many existing tests won’t need to be upgraded. Great news, isn’t it? 

Summary

React 18 will introduce a huge amount of new features and improved development performance, so it will be a massive update to the most loved JavaScript UI library. We are witnessing quite a change in the world of web applications, mainly due to concurrent mode and the rise of server-side rendering. The new features will also make a code easier to develop and maintain, and applications faster and more responsive for user interactions. We can’t wait for the official release and for more developers to add React to their tech stacks!

Looking for a reliable software development team?

We use cookies

We use cookies to make sure your website experience is as easy and as personal as possible. By accepting, you’re allowing them to do their job. Change your cookie preferences if you wish to.

Why? To analyze our visitor data, improve our website and show personalized content to our users. We want to give you a better experience of Massive Pixel Creation. Are you fine with this?