React 18: Everything you need to know

Tapajyoti Bose
4 min readApr 3, 2022

--

After the release of React 17 (famously known as the no-feature release), we finally have the stable version of React 18, which went live on 29th March 2022. Wondering what changed in the new version? This article got you covered!

Initialization Changes

If your app is using an old version of React, you can update it to the latest version using

npm install react@18.0.0 react-dom@18.0.0

OR

yarn add react@18.0.0 react-dom@18.0.0

There are no breaking changes in React 18, but the setup has been modified to utilize the new features. In the index file, there is a new syntax to plug in the React App.

// OLD METHOD:
import ReactDOM from "react-dom";
// ...
ReactDOM.render(<App />, document.getElementById("root"));
// NEW METHOD:
import ReactDOM from "react-dom/client";
// ...
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);

With that small tweak, you are good to go! You can now use the plethora of new features React 18 has to offer.

Concurrent Mode

If the entire React 18 update has to be summed up in one word, it would be Concurrency.

At a high level, concurrency basically means that tasks can overlap. Rather than one state update having to be fully complete before the system can move on to the next one, concurrency allows us to bounce back and forth between multiples.

It should be noted that this doesn’t mean those things are all happening at the same time — rather, it’s that one task can now be paused while other, more urgent tasks are completed.

Let’s take a look at the new APIs to utilize it!

useTransition

The useTransition hook is a new API that allows the users to mark any less-urgent actions as transitions and then tell React to let other, more urgent actions take priority in the rendering timeline.

The ideal use case of it would be when multiple non-urgent but computationally expensive tasks are being performed (eg: filtering a long list), which causes a delay in urgent tasks (eg: handling user input), resulting in a poor UX.

// POOR UX DUE TO FREEZING OF THE UI
const [input, setInput] = useState("");
const data = millionItems.filter((item) => item.includes(input));
const updateInput = (e) => setInput(e.target.value);
// GREAT UX DUE TO PRIORITIZATION
const [input, setInput] = useState("");
const [data, setData] = useState([...items]);
const [isPending, startTransition] = useTransition();
useEffect(() => {
startTransition(() => {
setData(items.filter((i) => i.includes(input)));
});
}, [input]);
const updateInput = (e) => setInput(e.target.value);

The isPending value can also be used to conditionally display a spinner to inform the user that some action is being performed in the background.

useDeferredValue

The new useDeferredValue hook allows us to select specific parts of our UI and intentionally defer updating them so they don't slow down other parts of our page. There are two nice things about this:

  1. Control over rendering order
  2. Ability to show previous or old values instead of just a loading animation or grey box.

In most cases, displaying a few pieces of stale data triumphs over showing a full-page loading animation.

Let’s take a look at how to use the hook:

const deferredValue = useDeferredValue(value);
return <MyComponent value={deferredValue} />;

Both the useTransition and useDeferredValue hooks take an additional parameter to specify the timeout in milliseconds.

// useTransition
const [isPending, startTransition] = useTransition({
timeoutMs: 3000,
});
// useDeferredValue
const deferredValue = useDeferredValue(value, {
timeoutMs: 3000,
});

Automatic Batching

Batching refers to grouping multiple state updates into a single re-render for better performance. This is great for performance because it avoids unnecessary re-renders.

Earlier React would batch changes due to browser actions, but not the state changes triggered inside Promises or Timeouts. In React 18, the developers overcame the hurdle and made it possible to batch all state updates.

// Before: only React events were batched.
setTimeout(() => {
setCount((c) => c + 1);
setFlag((f) => !f);
// React will render twice, once for each state update
}, 1000);
// After: updates inside of timeouts, promises,
// native event handlers or any other event are batched.
setTimeout(() => {
setCount((c) => c + 1);
setFlag((f) => !f);
// React will only re-render once at the end
}, 1000);

Streaming Server-Side Rendering

Server-Side Rendering is a technique where you render the HTML output of your React component, and then send that over to the client before the JS is ready so that the user is not stuck staring at a completely blank page. It has incredible performance and SEO benefits.

Before React 18, this was handled in an all-or-nothing approach — when all the components were ready, the page would be generated. That meant that if you had just one slow component, that one component could create a bottleneck.

This can be avoided using Suspense! We could wrap a single slow component in the Suspense tags and tell React to delay its loading and instead focus on sending down the other, smaller ones first. You can also set a fallback to show a loading animation:

<Suspense fallback={<Loading />}>
<SlowComponent />
</Suspense>

Now you are React 18 ready too!

Happy Developing!

Finding personal finance too intimidating? Checkout my Instagram to become a Dollar Ninja

Follow me for weekly new tidbits on the domain of tech

Need a Top Rated Front-End Development Freelancer to chop away your development woes? Contact me on Upwork

Want to see what I am working on? Check out my Personal Website and GitHub

Want to connect? Reach out to me on LinkedIn

--

--

Tapajyoti Bose
Tapajyoti Bose

Written by Tapajyoti Bose

Top Rated Freelancer || Blogger || Cross-Platform App Developer || Web Developer || Open Source Contributor || FIRE Enthusiast

Responses (5)