https://reactjs.org/blog/2022/03/29/react-v18.html
We want to hear from you!Take our 2021 Community Survey!
Support Ukraine Help Provide Humanitarian Aid to Ukraine.
[svg]ReactDocsTutorialBlogCommunity
[ ]
v18.0.0 LanguagesGitHub
React v18.0
March 29, 2022 by The React Team
React 18 is now available on npm!
In our last post, we shared step-by-step instructions for upgrading
your app to React 18. In this post, we'll give an overview of what's
new in React 18, and what it means for the future.
Our latest major version includes out-of-the-box improvements like
automatic batching, new APIs like startTransition, and streaming
server-side rendering with support for Suspense.
Many of the features in React 18 are built on top of our new
concurrent renderer, a behind-the-scenes change that unlocks powerful
new capabilities. Concurrent React is opt-in -- it's only enabled when
you use a concurrent feature -- but we think it will have a big impact
on the way people build applications.
We've spent years researching and developing support for concurrency
in React, and we've taken extra care to provide a gradual adoption
path for existing users. Last summer, we formed the React 18 Working
Group to gather feedback from experts in the community and ensure a
smooth upgrade experience for the entire React ecosystem.
In case you missed it, we shared a lot of this vision at React Conf
2021:
* In the keynote, we explain how React 18 fits into our mission to
make it easy for developers to build great user experiences
* Shruti Kapoor demonstrated how to use the new features in React
18
* Shaundai Person gave us an overview of streaming server rendering
with Suspense
Below is a full overview of what to expect in this release, starting
with Concurrent Rendering.
Note for React Native users: React 18 will ship in React Native with
the New React Native Architecture. For more information, see the
React Conf keynote here.
What is Concurrent React?
The most important addition in React 18 is something we hope you
never have to think about: concurrency. We think this is largely true
for application developers, though the story may be a bit more
complicated for library maintainers.
Concurrency is not a feature, per se. It's a new behind-the-scenes
mechanism that enables React to prepare multiple versions of your UI
at the same time. You can think of concurrency as an implementation
detail -- it's valuable because of the features that it unlocks. React
uses sophisticated techniques in its internal implementation, like
priority queues and multiple buffering. But you won't see those
concepts anywhere in our public APIs.
When we design APIs, we try to hide implementation details from
developers. As a React developer, you focus on what you want the user
experience to look like, and React handles how to deliver that
experience. So we don't expect React developers to know how
concurrency works under the hood.
However, Concurrent React is more important than a typical
implementation detail -- it's a foundational update to React's core
rendering model. So while it's not super important to know how
concurrency works, it may be worth knowing what it is at a high
level.
A key property of Concurrent React is that rendering is
interruptible. When you first upgrade to React 18, before adding any
concurrent features, updates are rendered the same as in previous
versions of React -- in a single, uninterrupted, synchronous
transaction. With synchronous rendering, once an update starts
rendering, nothing can interrupt it until the user can see the result
on screen.
In a concurrent render, this is not always the case. React may start
rendering an update, pause in the middle, then continue later. It may
even abandon an in-progress render altogether. React guarantees that
the UI will appear consistent even if a render is interrupted. To do
this, it waits to perform DOM mutations until the end, once the
entire tree has been evaluated. With this capability, React can
prepare new screens in the background without blocking the main
thread. This means the UI can respond immediately to user input even
if it's in the middle of a large rendering task, creating a fluid
user experience.
Another example is reusable state. Concurrent React can remove
sections of the UI from the screen, then add them back later while
reusing the previous state. For example, when a user tabs away from a
screen and back, React should be able to restore the previous screen
in the same state it was in before. In an upcoming minor, we're
planning to add a new component called that implements
this pattern. Similarly, you'll be able to use Offscreen to prepare
new UI in the background so that it's ready before the user reveals
it.
Concurrent rendering is a powerful new tool in React and most of our
new features are built to take advantage of it, including Suspense,
transitions, and streaming server rendering. But React 18 is just the
beginning of what we aim to build on this new foundation.
Gradually Adopting Concurrent Features
Technically, concurrent rendering is a breaking change. Because
concurrent rendering is interruptible, components behave slightly
differently when it is enabled.
In our testing, we've upgraded thousands of components to React 18.
What we've found is that nearly all existing components "just work"
with concurrent rendering, without any changes. However, some of them
may require some additional migration effort. Although the changes
are usually small, you'll still have the ability to make them at your
own pace. The new rendering behavior in React 18 is only enabled in
the parts of your app that use new features.
The overall upgrade strategy is to get your application running on
React 18 without breaking existing code. Then you can gradually start
adding concurrent features at your own pace. You can use
to help surface concurrency-related bugs during development. Strict
Mode doesn't affect production behavior, but during development it
will log extra warnings and double-invoke functions that are expected
to be idempotent. It won't catch everything, but it's effective at
preventing the most common types of mistakes.
After you upgrade to React 18, you'll be able to start using
concurrent features immediately. For example, you can use
startTransition to navigate between screens without blocking user
input. Or useDeferredValue to throttle expensive re-renders.
However, long term, we expect the main way you'll add concurrency to
your app is by using a concurrent-enabled library or framework. In
most cases, you won't interact with concurrent APIs directly. For
example, instead of developers calling startTransition whenever they
navigate to a new screen, router libraries will automatically wrap
navigations in startTransition.
It may take some time for libraries to upgrade to be concurrent
compatible. We've provided new APIs to make it easier for libraries
to take advantage of concurrent features. In the meantime, please be
patient with maintainers as we work to gradually migrate the React
ecosystem.
For more info, see our previous post: How to upgrade to React 18.
Suspense in Data Frameworks
In React 18, you can start using Suspense for data fetching in
opinionated frameworks like Relay, Next.js, Hydrogen, or Remix. Ad
hoc data fetching with Suspense is technically possible, but still
not recommended as a general strategy.
In the future, we may expose additional primitives that could make it
easier to access your data with Suspense, perhaps without the use of
an opinionated framework. However, Suspense works best when it's
deeply integrated into your application's architecture: your router,
your data layer, and your server rendering environment. So even long
term, we expect that libraries and frameworks will play a crucial
role in the React ecosystem.
As in previous versions of React, you can also use Suspense for code
splitting on the client with React.lazy. But our vision for Suspense
has always been about much more than loading code -- the goal is to
extend support for Suspense so that eventually, the same declarative
Suspense fallback can handle any asynchronous operation (loading
code, data, images, etc).
Server Components is Still in Development
Server Components is an upcoming feature that allows developers to
build apps that span the server and client, combining the rich
interactivity of client-side apps with the improved performance of
traditional server rendering. Server Components is not inherently
coupled to Concurrent React, but it's designed to work best with
concurrent features like Suspense and streaming server rendering.
Server Components is still experimental, but we expect to release an
initial version in a minor 18.x release. In the meantime, we're
working with frameworks like Next.js, Hydrogen, and Remix to advance
the proposal and get it ready for broad adoption.
What's New in React 18
New Feature: Automatic Batching
Batching is when React groups multiple state updates into a single
re-render for better performance. Without automatic batching, we only
batched updates inside React event handlers. Updates inside of
promises, setTimeout, native event handlers, or any other event were
not batched in React by default. With automatic batching, these
updates will be batched automatically:
// Before: only React events were batched.
setTimeout(() => {
setCount(c => c + 1);
setFlag(f => !f);
// React will render twice, once for each state update (no batching)
}, 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 (that's batching!)
}, 1000);
For more info, see this post for Automatic batching for fewer renders
in React 18.
New Feature: Transitions
A transition is a new concept in React to distinguish between urgent
and non-urgent updates.
* Urgent updates reflect direct interaction, like typing, clicking,
pressing, and so on.
* Transition updates transition the UI from one view to another.
Urgent updates like typing, clicking, or pressing, need immediate
response to match our intuitions about how physical objects behave.
Otherwise they feel "wrong". However, transitions are different
because the user doesn't expect to see every intermediate value on
screen.
For example, when you select a filter in a dropdown, you expect the
filter button itself to respond immediately when you click. However,
the actual results may transition separately. A small delay would be
imperceptible and often expected. And if you change the filter again
before the results are done rendering, you only care to see the
latest results.
Typically, for the best user experience, a single user input should
result in both an urgent update and a non-urgent one. You can use
startTransition API inside an input event to inform React which
updates are urgent and which are "transitions":
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);
});
Updates wrapped in startTransition are handled as non-urgent and will
be interrupted if more urgent updates like clicks or key presses come
in. If a transition gets interrupted by the user (for example, by
typing multiple characters in a row), React will throw out the stale
rendering work that wasn't finished and render only the latest
update.
* useTransition: a hook to start transitions, including a value to
track the pending state.
* startTransition: a method to start transitions when the hook
cannot be used.
Transitions will opt in to concurrent rendering, which allows the
update to be interrupted. If the content re-suspends, transitions
also tell React to continue showing the current content while
rendering the transition content in the background (see the Suspense
RFC for more info).
See docs for transitions here.
New Suspense Features
Suspense lets you declaratively specify the loading state for a part
of the component tree if it's not yet ready to be displayed:
}>
Suspense makes the "UI loading state" a first-class declarative
concept in the React programming model. This lets us build
higher-level features on top of it.
We introduced a limited version of Suspense several years ago.
However, the only supported use case was code splitting with
React.lazy, and it wasn't supported at all when rendering on the
server.
In React 18, we've added support for Suspense on the server and
expanded its capabilities using concurrent rendering features.
Suspense in React 18 works best when combined with the transition
API. If you suspend during a transition, React will prevent
already-visible content from being replaced by a fallback. Instead,
React will delay the render until enough data has loaded to prevent a
bad loading state.
For more, see the RFC for Suspense in React 18.
New Client and Server Rendering APIs
In this release we took the opportunity to redesign the APIs we
expose for rendering on the client and server. These changes allow
users to continue using the old APIs in React 17 mode while they
upgrade to the new APIs in React 18.
React DOM Client
These new APIs are now exported from react-dom/client:
* createRoot: New method to create a root to render or unmount. Use
it instead of ReactDOM.render. New features in React 18 don't
work without it.
* hydrateRoot: New method to hydrate a server rendered application.
Use it instead of ReactDOM.hydrate in conjunction with the new
React DOM Server APIs. New features in React 18 don't work
without it.
Both createRoot and hydrateRoot accept a new option called
onRecoverableError in case you want to be notified when React
recovers from errors during rendering or hydration for logging. By
default, React will use reportError, or console.error in the older
browsers.
See docs for React DOM Client here.
React DOM Server
These new APIs are now exported from react-dom/server and have full
support for streaming Suspense on the server:
* renderToPipeableStream: for streaming in Node environments.
* renderToReadableStream: for modern edge runtime environments,
such as Deno and Cloudflare workers.
The existing renderToString method keeps working but is discouraged.
See docs for React DOM Server here.
New Strict Mode Behaviors
In the future, we'd like to add a feature that allows React to add
and remove sections of the UI while preserving state. For example,
when a user tabs away from a screen and back, React should be able to
immediately show the previous screen. To do this, React would unmount
and remount trees using the same component state as before.
This feature will give React apps better performance out-of-the-box,
but requires components to be resilient to effects being mounted and
destroyed multiple times. Most effects will work without any changes,
but some effects assume they are only mounted or destroyed once.
To help surface these issues, React 18 introduces a new
development-only check to Strict Mode. This new check will
automatically unmount and remount every component, whenever a
component mounts for the first time, restoring the previous state on
the second mount.
Before this change, React would mount the component and create the
effects:
* React mounts the component.
* Layout effects are created.
* Effects are created.
With Strict Mode in React 18, React will simulate unmounting and
remounting the component in development mode:
* React mounts the component.
* Layout effects are created.
* Effects are created.
* React simulates unmounting the component.
* Layout effects are destroyed.
* Effects are destroyed.
* React simulates mounting the component with the previous state.
* Layout effects are created.
* Effects are created.
See docs for ensuring resusable state here.
New Hooks
useId
useId is a new hook for generating unique IDs on both the client and
server, while avoiding hydration mismatches. It is primarily useful
for component libraries integrating with accessibility APIs that
require unique IDs. This solves an issue that already exists in React
17 and below, but it's even more important in React 18 because of how
the new streaming server renderer delivers HTML out-of-order. See
docs here.
useTransition
useTransition and startTransition let you mark some state updates as
not urgent. Other state updates are considered urgent by default.
React will allow urgent state updates (for example, updating a text
input) to interrupt non-urgent state updates (for example, rendering
a list of search results). See docs here
useDeferredValue
useDeferredValue lets you defer re-rendering a non-urgent part of the
tree. It is similar to debouncing, but has a few advantages compared
to it. There is no fixed time delay, so React will attempt the
deferred render right after the first render is reflected on the
screen. The deferred render is interruptible and doesn't block user
input. See docs here.
useSyncExternalStore
useSyncExternalStore is a new hook that allows external stores to
support concurrent reads by forcing updates to the store to be
synchronous. It removes the need for useEffect when implementing
subscriptions to external data sources, and is recommended for any
library that integrates with state external to React. See docs here.
Note
useSyncExternalStore is intended to be used by libraries, not
application code.
useInsertionEffect
useInsertionEffect is a new hook that allows CSS-in-JS libraries to
address performance issues of injecting styles in render. Unless
you've already built a CSS-in-JS library we don't expect you to ever
use this. This hook will run after the DOM is mutated, but before
layout effects read the new layout. This solves an issue that already
exists in React 17 and below, but is even more important in React 18
because React yields to the browser during concurrent rendering,
giving it a chance to recalculate layout. See docs here.
Note
useInsertionEffect is intended to be used by libraries, not
application code.
Changelog
React
* Add useTransition and useDeferredValue to separate urgent updates
from transitions. (#10426, #10715, #15593, #15272, #15578, #15769
, #17058, #18796, #19121, #19703, #19719, #19724, #20672, #20976
by @acdlite, @lunaruan, @rickhanlonii, and @sebmarkbage)
* Add useId for generating unique IDs. (#17322, #18576, #22644, #
22672, #21260 by @acdlite, @lunaruan, and @sebmarkbage)
* Add useSyncExternalStore to help external store libraries
integrate with React. (#15022, #18000, #18771, #22211, #22292, #
22239, #22347, #23150 by @acdlite, @bvaughn, and @drarmstr)
* Add startTransition as a version of useTransition without pending
feedback. (#19696 by @rickhanlonii)
* Add useInsertionEffect for CSS-in-JS libraries. (#21913 by
@rickhanlonii)
* Make Suspense remount layout effects when content reappears. (#
19322, #19374, #19523, #20625, #21079 by @acdlite, @bvaughn, and
@lunaruan)
* Make re-run effects to check for restorable state. (
#19523 , #21418 by @bvaughn and @lunaruan)
* Assume Symbols are always available. (#23348 by @sebmarkbage)
* Remove object-assign polyfill. (#23351 by @sebmarkbage)
* Remove unsupported unstable_changedBits API. (#20953 by @acdlite)
* Allow components to render undefined. (#21869 by @rickhanlonii)
* Flush useEffect resulting from discrete events like clicks
synchronously. (#21150 by @acdlite)
* Suspense fallback={undefined} now behaves the same as null and
isn't ignored. (#21854 by @rickhanlonii)
* Consider all lazy() resolving to the same component equivalent. (
#20357 by @sebmarkbage)
* Don't patch console during first render. (#22308 by @lunaruan)
* Improve memory usage. (#21039 by @bgirard)
* Improve messages if string coercion throws (Temporal.*, Symbol,
etc.) (#22064 by @justingrant)
* Use setImmediate when available over MessageChannel. (#20834 by
@gaearon)
* Fix context failing to propagate inside suspended trees. (#23095
by @gaearon)
* Fix useReducer observing incorrect props by removing the eager
bailout mechanism. (#22445 by @josephsavona)
* Fix setState being ignored in Safari when appending iframes. (#
23111 by @gaearon)
* Fix a crash when rendering ZonedDateTime in the tree. (#20617 by
@dimaqq)
* Fix a crash when document is set to null in tests. (#22695 by
@SimenB)
* Fix onLoad not triggering when concurrent features are on. (#
23316 by @gnoff)
* Fix a warning when a selector returns NaN. (#23333 by @hachibeeDI
)
* Fix a crash when document is set to null in tests. (#22695 by
@SimenB)
* Fix the generated license header. (#23004 by @vitaliemiron)
* Add package.json as one of the entry points. (#22954 by @Jack)
* Allow suspending outside a Suspense boundary. (#23267 by @acdlite
)
* Log a recoverable error whenever hydration fails. (#23319 by
@acdlite)
React DOM
* Add createRoot and hydrateRoot. (#10239, #11225, #12117, #13732,
#15502, #15532, #17035, #17165, #20669, #20748, #20888, #21072, #
21417, #21652, #21687, #23207, #23385 by @acdlite, @bvaughn,
@gaearon, @lunaruan, @rickhanlonii, @trueadm, and @sebmarkbage)
* Add selective hydration. (#14717, #14884, #16725, #16880, #17004,
#22416, #22629, #22448, #22856, #23176 by @acdlite, @gaearon,
@salazarm, and @sebmarkbage)
* Add aria-description to the list of known ARIA attributes. (#
22142 by @mahyareb)
* Add onResize event to video elements. (#21973 by @rileyjshaw)
* Add imageSizes and imageSrcSet to known props. (#22550 by
@eps1lon)
* Allow non-string