React 18 - Should you upgrade?
Last week, React 18 was officially announced and even though we still don’t have an exact release date - apart from sometime early next year – it looks really promising!
It has new features like automatic state batching, new server side rendering architecture with selective hydration, new API’s for application developers like startTransition and useDeferredValue and last but not least concurrency mode which gives the ability to execute multiple tasks simultaneously.
Automatic batching
Batching is when React groups multiple state updates into a single re-render for better performance. This is great for performance because it avoids unnecessary re-renders. It also prevents components from rendering “half-finished” states where only one state variable was updated, which may cause bugs. [1]
Until React 18, batched updates were only happening during the React event handlers. Updates inside promises, setTimeout, native event handlers, or other events were not batched in React by default.
function App() {
const [count, setCount] = useState(0);
const [flag, setFlag] = useState(false);
function handleClick() { //React 17 and 18
setCount(c => c + 1); // Does not re-render yet
setFlag(f => !f); // Does not re-render yet
// React will only re-render once at the end (that's batching!)
}
function handleClick() { //React 17
fetchSomething().then(() {
// React 17 and earlier does NOT batch these because
// they run *after* the event in a callback, not *during* it
setCount(c => c + 1); // Causes a re-render
setFlag(f => !f); // Causes a re-render
});
}
function handleClick() { //React 18
fetchSomething().then(() {
// React 18 and later DOES batch these:
setCount(c => c + 1);
setFlag(f => !f);
// React will only re-render once at the end (that's batching!)
});
}
..........
}
With React 18 and createRoot, all updates will be automatically batched, no matter where they originate from. This means that updates inside timeouts, promises, native event handlers or other events will batch the same way as updates inside React events resulting in less work rendering, and therefore better performance in applications.
SSR and selective hydration
Server-side rendering (SSR) is a technique for rendering the HTML from React components on the server and then sending a fully rendered page to the client, allowing users to see the page’s content before JavaScript bundle loads and runs. [2]
SSR in React always happens in several steps:
- On the server, fetch data for the entire app.
- Then, on the server, render the entire app to HTML and send it in the response.
- Then, on the client, load the JavaScript code for the entire app.
- Then, on the client, connect the JavaScript logic to the server-generated HTML for the entire app (this is “hydration”).
Before React 18, SSR in react was an all or nothing thing. Each step had to finish the entire app at once before the next step could start. This means that if a part of the application is slower than another, it'll block the entire application, making it inefficient.
With React 18 and the use of and Selective hydration, it’s possible to break down the application into smaller independent units which will go through these steps independently from each other and won’t block the rest of the app. Consequently, users will see the content of the application sooner and be able to start interacting with it much faster while the slowest parts of the app won’t drag down the parts that are fast.
New API’s for application developers
React 18 adds a few new API’s called concurrent features that can improve the performance of an application by marking some state updates as non-urgent thus keeping the browser responsive. Some of them are:
- startTransition()
- useTransitions()
- useDeferredValues()
One important use case for startTransition could be when a user clicks on a button or starts typing in an input field. The button or the input value has to be immediately updated and the results of those actions could cause a delay for the user while all of the work is being done, thus causing the page to freeze or hang. [3]
Until React 18, debouncing or throttling state updates were the best solution to this problem.
With React 18 and startTransition, the user will receive fast feedback for the button click or input typing, and begin rendering the results of those actions in the background so that they’re rendered as soon as they’re available without any long tasks lagging the page.
Upgrading and the New Root API
The React 18 upgrade process is pretty straightforward and it should be a smooth experience for most users. One major difference is the new Root API
import React from 'react';
import ReactDOM from 'react-dom';
import App from 'App';
const container = document.getEleementById('root');
const root = ReactDOM.createRoot(container);
root.render(<Αpp />);
React 18 will offer a performance boost to applications even by just upgrading to the new version with minimal or no changes to application code and the best part is that it gives users the option adopt the new version without rewrites and try the new features at their own pace.
Take a look at our Solutions page to see where we can help.
References
[1]: https://github.com/reactwg/react-18/discussions/21
[2]: https://github.com/reactwg/react-18/discussions/37
[3]: https://www.freecodecamp.org/news/whats-new-in-react-18/