React 18: The Features and The Future
All about the exciting release of React 18 and exploring its new features
The web development space is in a constant state of evolution, with technologies needing to adapt to frequent changes. In this dynamic environment, there is an ever-increasing demand for greater efficiency and optimized performance. Popular frameworks like React have evolved over the years to meet these demands, providing developers with enhanced tools for productivity and effectiveness. In this article, we’ll look at the latest development in the React ecosystem and the benefits it brings for both developers and users alike.
Table of Contents
What is React?
React v18.0
How to upgrade to React 18
Conclusion
PS: This will be a lengthy read, so grab your juice, relax on your couch and let’s get this going. 😉
What is React?
React also known as React JS is a popular open-source JavaScript library for building user interfaces. React helps developers create interactive and dynamic web applications through the use of a component-based architecture and a virtual DOM. This means that the user interface is broken down into reusable and self-contained building blocks. React helps build fast and modern web applications.
React was developed by Facebook in 2011 and released to the public in 2013. React 16.0 was released in September 2017, while React 17.0 was released in August 2020. On March 29, 2022, React 18 was released, which introduced new features.
React v18.0
As earlier stated, on March 29, 2022, React 18 was rolled out with some key updates and new features. React 18 is focused on improving the performance of React applications and concurrent rendering features. You can check out the official release document here.
There is an improvement to concurrency in React and new features added, which include:
Automatic Batching
Transitions
Suspense on the server
New Strict Mode Behaviors
New Hooks
We’ll look at these improvements and features in detail.
Concurrent React
Concurrent React is a feature that allows applications to stay responsive and gracefully adjust to varying workloads and priorities. It helps React prioritize updates and rendering based on the importance and urgency of different tasks, ensuring that high-priority updates are processed more quickly.
In previous versions of React, once rendering started, it could not be interrupted until it was completed.
Dan Abramov from the React 18 working group discussions gives a good example that simplifies the concept of concurrency.
Let’s say we need to call two people, Bob and Alice. In a non-concurrent setting, we’ll place the calls to each of them one after the other; that is, I call Bob first, and after ending the call with him, I call Alice.
Let’s imagine a scenario where we are talking with Alice and an urgent call from Bob comes in. We put the call with Alice on hold and then answer the more urgent call from Bob before going back to our call with Alice. This is what concurrency is.
In React 18, React can either interrupt, pause, or resume a render. It can even go as far as abandoning it to quickly respond to user interactions. It does not matter the magnitude of the task at hand; when there is a more urgent task, React will treat that as a priority.
Automatic Batching
Automatic batching is one of the features of React 18. To understand batching, an example is given from the React 18 working group discussion. Let’s say five of your friends are around on a visit, and you want to get food for them from a nearby restaurant. To ensure your trip is efficient, you get a list of what each person wants to eat, take a trip to the restaurant, and buy the food, all in a single trip. This is batching.
Without batching, you would get the order of the first person, go to the restaurant, purchase the food, and come back to take the order of the second person, go to the restaurant, purchase the food... until you do so for the last person. You would be so frustrated.
React uses batching to group multiple state updates into a single re-render for better performance. By doing this, unnecessary re-renders are avoided. Previously, React batched state updates in event handlers during browser events, as shown below:
function App() {
const [count, setCount] = useState(0);
const [alert, setAlert] = useState(false);
const handleClick =()=>{
setCount(count => count + 1);
setAlert(alert => !alert);
// React re-renders once at the end. This is batching!
}
return (
<div>
<button onClick={handleClick}>Increment</button>
<h1 classname={`${alert ? "bg-blue " : "bg-black"}`}>
{count}</h1>
</div>
);
}
However, there were some exceptions to this, such as updating the state after an event has been handled. For example, if you need to fetch data and then update the state in the event handler handleClick
above, React would not batch the updates but do them independently.
function App() {
const [count, setCount] = useState(0);
const [alert, setAlert] = useState(false);
const handleClick =()=>{
fetch().then(() => {
setCount(count => count + 1); // React re-renders this!
setAlert(alert => !alert); // React re-renders this!
});
}
return (
<div>
<button onClick={handleClick}>Increment</button>
<h1 classname={`${alert ? "bg-blue " : "bg-black"}`}>{count}</h1>
</div>
);
}
In React 18, createRoot
helps to automatically batch all updates, irrespective of whether they are in event handlers or not.
Automatic batching comes with React 18. UseReactDOM.flushSync()
to opt out of batching.
Transitions
Transition is a newly introduced feature that helps React distinguish urgent from non-urgent updates.
Urgent updates are from the direct interaction of the user, such as pressing, typing, clicking, and more.
Transition updates or non-urgent updates switch the UI from one view to another.
Transition ensures that the user interface remains responsive even during a re-render. For example, you may have done this before. You click a button, and before the information is fully loaded, you change your mind and click on another button to do another task.
What did you notice? The action you took caused the user interface to freeze briefly. This happens when the state update is not set to a transition. Transition interrupts an ongoing render in favour of a more urgent one.
Updates are marked with the useTransition()
hook. Here’s an example of how transition works, as adapted from the React blog.
function SlidesContainer() {
const [isPending, startTransition] = useTransition();
const [slide, setSlide] = useState('about');
function selectSlide(nextSlide) {
startTransition(() => {
setSlide(nextSlide);
});
}
// ...
}
Also, the React blog explains what isPending
and do.
“The
*isPending*
flag that tells you whether there is a pending transition.”
“The*startTransition*
function that lets you mark a state update as a transition”
The startTransition
function can be used to start transitions whenever the useTransition()
hook cannot be used. Here’s an example from the React blog.
import { startTransition } from 'react';
// Urgent: Show what was typed
setInputValue(input);
// Mark any state updates inside as transitions
startTransition(() => {
// Transition: Show the results
setSearchQuery(input);
});
You can learn more about transitions in the transition documentation.
Suspense on the Server
When rendering your client-side application, you first fetch the HTML of the page from the server and the required JavaScript resources necessary to run the page. However, if you’re faced with challenges such as a large JavaScript bundle size or a slow network connection, delays occur, preventing the user from effectively interacting with the page.
Server-side rendering (SSR) takes care of this and ensures the user experience is enjoyable.
Server rendering, also known as server-side rendering (SSR), is a web development technique where a web server processes a request for a web page and generates the initial HTML content. This HTML is sent to the user’s browser, which can then render the page faster since it already has some content to display.
This is done while JavaScript content is still loading, hence, the pages are static and will only become interactive after the necessary JavaScript contents have loaded.
Shaundai Person’s React Conf 2021 talk gives a detailed overview of client vs. server-side rendering.
Previously, in React, one slow component meant the entire page would also render slowly. There was no way you could tell React to defer the loading of a slow component. This caused bottlenecks in React apps.
In React 18, you can “suspend” slow parts or components of your app by wrapping them in the Suspense components. For example, you can show a loading state for a component that would take a bit of time to load.
As explained on the React blog, “suspense lets you declaratively specify the loading state for a part of the component tree if it’s not yet ready to be displayed”
When a component is “suspended”, it means it is not ready to load, so HTML is sent directly from the server to display on the page while the component gets ready to be displayed. The user is then able to see a skeleton of the page immediately before it gradually loads.
Since HTML is lightweight, it is displayed before JavaScript; hence, there will be HTML components on display while the JavaScript components are gradually loading, improving the user experience.
New Strict Mode Behaviours
In React 18, strict mode will simulate the mounting, unmounting, and remounting of components with a previous state. What does this mean? For example, when a user tabs away from a screen and back, the previous screen should be immediately seen. I’ll explain the process:
When the user gets to the screen at first, React mounts the component
When the user tabs away from the screen, React dismounts the component
When the user goes back to the screen, React mounts the component again.
This is done over and over again. Strict mode will make sure that components are not affected by being mounted and unmounted over and over again.
New Hooks
React 18 introduces new hooks, such as
You can read more about them.
How to Upgrade to React 18
To install React 18 and React DOM from npm, type this in your terminal:
npm install react react-dom
If you’re using yarn, type the following into your terminal:
yarn add react react-dom
Then, you’ll use createRoot
instead of render
.
In your index.js file, update ReactDOM.render
to ReactDOM.createRoot
to create a root and render your app using root.
In React 17, this was the format:
import ReactDOM from 'react-dom';
import App from 'App';
const container = document.getElementById('app');
// render app to ReactDOM directly
ReactDOM.render(<App />, container);
In React 18, this has been updated to:
import ReactDOM from 'react-dom';
import App from 'App';
const container = document.getElementById('app');
// create a root
const root = ReactDOM.createRoot(container);
//render app to root
root.render(<App />);
Your React app will continue to be recognized as version 17 until you apply the updates.
Conclusion
Whew! That was quite a lot, and so much more. These improvements and features in React bode well for developers and users alike. It ensures a smoother developer's experience and eliminates performance bottlenecks, leading to faster React applications.
The user experience has also been improved. No more looking at blank screens waiting for the components of a page to load (hehehe). There’s also improved interactivity and seamless running of tasks for the users. So, this is a win-win situation. The future of React looks very bright. Long may React continue!
Top comments (0)