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:
- Control over rendering order
- 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
Thanks for reading
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
I am a freelancer who will start off as a Digital Nomad in mid-2022. Want to catch the journey? Follow me on Instagram
Follow my blogs for Weekly new Tidbits on Dev
FAQ
These are a few commonly asked questions I get. So, I hope this FAQ section solves your issues.
-
I am a beginner, how should I learn Front-End Web Dev?
Look into the following articles:
Top comments (1)
I really liked this article! In essence, the component simplifies the asynchronous data fetching process and loading display. It can be wrapped around a component that handles the data fetching, enabling developers to display a loader component coded in a declarative way in their layout.
Now we can see the loading logic has been removed from within the Async component, which offers several benefits.
First, the loading logic is now independent of the data fetching component. This means that we can change the design of how an app displays loading sequences without having to modify the code of individual components.
Second, we can nest components within each other, allowing us to show a loader for an entire section, as well as for subcomponents with loaders.
Finally, the suspendable version of the data fetching component is now much cleaner and easier to maintain. I would recommend reading this article from my colleague Will Eizlini, that clearly explains some examples using : scalablepath.com/react/react-18-re...