Amazing new features in React 18
React 18 was released, and we were eager to jump in and check out what's new in the latest version of this fantastic framework.
Concurrency
One of the most critical changes is concurrent React. React has updated its rendering model, allowing for better handling of concurrent tasks behind the scenes. It takes the weight of handling complicated rendering logic while allowing for performant concurrent tasks to be held, always providing a functional UI to the end-user without interrupting the main thread.
These concurrent changes are not exactly a feature but rather a shift in the implementation that you can opt-in when you upgrade to React 18.
However, this might be an issue for some libraries you might use. According to the React team, adopting concurrent rendering should be straightforward overall, so libraries should be able to adapt quickly. You can check a partial list of compatible libraries here.
In the meantime, you can use useTransition and useDeferredValue to implement concurrent features.
The next one is exciting: automatic batching has been improved in React. In React 17 automatic batching would only occur for browser events and hooks. Many significant operations would then miss the benefits of automatic batching.
You can test this on a React 17 app by writing a simple button with two state changes.
You can test this on this code sandbox.
If you execute this component, you will see that it will only render once for each click. However, if we decide to update these states after some async action, you will see that the component will render twice.
You can test this on this code sandbox, and the React 18 counterpart here.
However, in React 18 this is not the case. If you start using the new rendering API (shown later) you will be able to harness the power of automatic batching.
Transitions and deferred values
React 18 also brings a new concept to the table: transitions. This new feature allows for detailed updates as urgent or non-urgent.
Urgent updates need to be immediate, or the UX will feel off. In contrast, non-urgent can wait and don't need to be direct. You can start using them by wrapping your state change with startTransition
:
The updates wrapped inside startTransition
can be interrupted by more urgent updates. You can use this alongside concurrent rendering (shown by the fact that transitions can be interrupted).
For cases where you don't handle the state but rather the value, you can use useDeferredValue
to wrap the value.
For example, the input will be immediately updated inside the following component. However, the value defferedValue can be delayed to at most 3000 milliseconds (3 seconds):
You can check this out in this code sandbox.
Client and Server rendering API
The last change we will cover, but not least important, is the new Client and Server rendering API.
For react client It adds the method createRoot
and hydrateRoot
that replace the previous ReactDOM.render
and ReactDOM.hydrate
respectively.
and
The purpose of this addition is to allow the use of the previous method for compatibility reasons while also allowing the new React 18 features to be used without causing breaking changes.
These new methods accept an option named onRecoverableError
as a callback to handle an event for when React recovers from an error during rendering or hydration.
For React DOM Server, we now have renderToPipeableStream
for streaming Node environments and renderToReadableStream
for runtimes like Deno and Cloudflare workers. There are also more hooks and additional changes that you can check out in React's blog post.