Browse Source

React 18 (#4499)

* [18] ReactDOM reference to createRoot/hydrateRoot (#4340)

* [18] ReactDOM reference to createRoot/hydrateRoot

* Update note about render and hydrate

* Match the warning text

* s/Render/render

* [18] Update ReactDOMClient docs (#4468)

* [18] Update ReactDOMClient docs

* Remove ReactDOMClient where it's obvious

* Update browser message

* Update browser message note

* Update based on feedback

* Add react-dom/client docs

* [18] Upgrade homepage examples (#4469)

* [18] Switch code samples to createRoot (#4470)

* [18] Switch code samples to createRoot

* Feedback fixes

* Feedback updates

* [18] Use hydrateRoot and root.unmount. (#4473)

* [18] Add docs for flushSync (#4474)

* [18] Add flushSync to ReactDOM docs

* Seb feedback

* More Seb feedback

* [18] Bump version to 18 (#4478)

* [18] Update browser requirements (#4476)

* [18] Update browser requirements

* Update based on feedback

* [18] Add stubs for new API references (#4477)

* [18] Add stubs for new API references

* Change order/grouping

* [18] Redirect outdated Concurrent Mode docs (#4481)

* [18] Redirect outdated Concurrent Mode docs

* Use Vercel redirects instead

* [18] Update versions page (#4482)

* [18] Update version page

* Fix prettier

* [18] Update React.lazy docs (#4483)

* [18] Add docs for useSyncExternalStore (#4487)

* [18] Add docs for useSyncExternalStore

* rm "optional"

* [18] Add docs for useInsertionEffect (#4486)

* [18] Add docs for useId (#4488)

* [18] Add docs for useId

* Update based on feedback

* Add Strict Effects to Strict Mode (#4362)

* Add Strict Effects to Strict Mode

* Update with new thinking

* [18] Update docs for useEffect timing (#4498)

* [18] Add docs for useDeferredValue (#4497)

* [18] Update suspense docs for unexpected fallbacks (#4500)

* [18] Update suspense docs for unexpected fallbacks

* Add inline code block

* Feedback fixes

* [18] Updated Suspense doc with behavior during SSR and Hydration (#4484)

* update wording

* wording

* update events

* Update content/docs/reference-react.md

Co-authored-by: Sebastian Silbermann <silbermann.sebastian@gmail.com>

* add link to selective hydration

* remove some of the implementation details

Co-authored-by: Sebastian Silbermann <silbermann.sebastian@gmail.com>

* [18] renderToPipeableStream doc (#4485)

* new streaming ssr api

* add readable stream

* code snippets

* Rename strict effects / unsafe effects to use the reusable state terminology (#4505)

* Add draft of 18 release post

* Add links to speaker Twitter profiles

* [18] Update upgrade guide

* Fix typo in blog title

* [18] Blog - add note for react native

* [18] Add changelog info to blog posts

* Edit Suspense for data fetching section

* Update date

* [18] Add links

* Consistent title case

* Update link to merged RFC

* [18] Update APIs and links

* [18] Add start/useTransition docs (#4479)

* [18] Add start/useTransition docs

* Updates based on feedback

* [18] Generate heading IDs

* Add note about Strict Mode

* Just frameworks

* Reorder, fix content

* Typos

* Clarify Suspense frameworks section

* Revert lost changes that happened when I undo-ed in my editor

Co-authored-by: salazarm <salazarm@users.noreply.github.com>
Co-authored-by: Sebastian Silbermann <silbermann.sebastian@gmail.com>
Co-authored-by: Sebastian Markbåge <sebastian@calyptus.eu>
Co-authored-by: Andrew Clark <git@andrewclark.io>
Co-authored-by: dan <dan.abramov@gmail.com>
main
Ricky 3 years ago
committed by GitHub
parent
commit
74246c13b9
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      beta/src/pages/apis/reactdom.md
  2. 19
      beta/src/pages/learn/add-react-to-a-website.md
  3. 3
      content/authors.yml
  4. 73
      content/blog/2022-03-08-react-18-upgrade-guide.md
  5. 323
      content/blog/2022-03-29-react-v18.md
  6. 2
      content/community/conferences.md
  7. 7
      content/docs/add-react-to-a-website.md
  8. 2
      content/docs/addons-shallow-renderer.md
  9. 6
      content/docs/addons-test-utils.md
  10. 50
      content/docs/code-splitting.md
  11. 13
      content/docs/components-and-props.md
  12. 144
      content/docs/concurrent-mode-adoption.md
  13. 103
      content/docs/concurrent-mode-intro.md
  14. 940
      content/docs/concurrent-mode-patterns.md
  15. 204
      content/docs/concurrent-mode-reference.md
  16. 739
      content/docs/concurrent-mode-suspense.md
  17. 4
      content/docs/forms.md
  18. 5
      content/docs/handling-events.md
  19. 9
      content/docs/hello-world.md
  20. 4
      content/docs/hooks-faq.md
  21. 206
      content/docs/hooks-reference.md
  22. 11
      content/docs/implementation-notes.md
  23. 40
      content/docs/integrating-with-other-libraries.md
  24. 10
      content/docs/introducing-jsx.md
  25. 38
      content/docs/lists-and-keys.md
  26. 2
      content/docs/nav.yml
  27. 3
      content/docs/portals.md
  28. 6
      content/docs/react-without-es6.md
  29. 18
      content/docs/react-without-jsx.md
  30. 2
      content/docs/reference-dom-elements.md
  31. 10
      content/docs/reference-glossary.md
  32. 27
      content/docs/reference-javascript-environment-requirements.md
  33. 86
      content/docs/reference-react-dom-client.md
  34. 91
      content/docs/reference-react-dom-server.md
  35. 98
      content/docs/reference-react-dom.md
  36. 48
      content/docs/reference-react.md
  37. 8
      content/docs/rendering-elements.md
  38. 49
      content/docs/state-and-lifecycle.md
  39. 49
      content/docs/strict-mode.md
  40. 2
      content/docs/testing-recipes.md
  41. 2
      content/docs/thinking-in-react.md
  42. 6
      content/docs/typechecking-with-proptypes.md
  43. 3
      content/docs/web-components.md
  44. 5
      content/home/examples/a-component-using-external-plugins.js
  45. 11
      content/home/examples/a-simple-component.js
  46. 5
      content/home/examples/a-stateful-component.js
  47. 5
      content/home/examples/an-application.js
  48. 23
      content/versions.yml
  49. 5
      examples/rendering-elements/render-an-element.js
  50. 6
      examples/rendering-elements/update-rendered-element.js
  51. 11
      src/components/CodeEditor/CodeEditor.js
  52. 9
      src/pages/versions.js
  53. 2
      src/site-constants.js
  54. 27
      vercel.json

4
beta/src/pages/apis/reactdom.md

@ -22,10 +22,10 @@ npm install react-dom
```js
// Importing a specific API:
import { render } from 'react-dom';
import { createRoot } from 'react-dom/client';
// Importing all APIs together:
import * as ReactDOM from 'react';
import * as ReactDOMClient from 'react-dom/client';
```
</PackageImport>

19
beta/src/pages/learn/add-react-to-a-website.md

@ -74,11 +74,12 @@ function LikeButton() {
### Step 4: Add your React Component to the page {/*step-4-add-your-react-component-to-the-page*/}
Lastly, add two lines to the bottom of **like_button.js**. These two lines of code find the `<div>` you added to your HTML in the first step and then display the "Like" button React component inside of it.
Lastly, add three lines to the bottom of **like_button.js**. These three lines of code find the `<div>` you added to your HTML in the first step, create a React app with it, and then display the "Like" button React component inside of it.
```js
const domContainer = document.getElementById('component-goes-here');
ReactDOM.render(React.createElement(LikeButton), domContainer);
const root = ReactDOM.createRoot(domContainer);
root.render(React.createElement(LikeButton));
```
**Congratulations! You have just rendered your first React component to your website!**
@ -88,21 +89,21 @@ ReactDOM.render(React.createElement(LikeButton), domContainer);
#### You can reuse components! {/*you-can-reuse-components*/}
You might want to display a React component in multiple places on the same HTML page. This is most useful while React-powered parts of the page are isolated from each other. You can do this by calling `ReactDOM.render()` multiple times with multiple container elements.
You might want to display a React component in multiple places on the same HTML page. This is most useful while React-powered parts of the page are isolated from each other. You can do this by calling `ReactDOM.createRoot()` multiple times with multiple container elements.
1. In **index.html**, add an additional container element `<div id="component-goes-here-too"></div>`.
2. In **like_button.js**, add an additional `ReactDOM.render()` for the new container element:
```js {6,7,8,9}
ReactDOM.render(
React.createElement(LikeButton),
const root1 = ReactDOM.createRoot(
document.getElementById('component-goes-here')
);
root1.render(React.createElement(LikeButton));
ReactDOM.render(
React.createElement(LikeButton),
const root2 = ReactDOM.createRoot(
document.getElementById('component-goes-here-too')
);
root2.render(React.createElement(LikeButton));
```
Check out [an example that displays the "Like" button three times and passes some data to it](https://gist.github.com/rachelnabors/c0ea05cc33fbe75ad9bbf78e9044d7f8)!
@ -157,8 +158,8 @@ Now you can use JSX in any `<script>` tag by adding `type="text/babel"` attribut
```jsx {1}
<script type="text/babel">
ReactDOM.render(
<h1>Hello, world!</h1>, document.getElementById('root') );
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<h1>Hello, world!</h1>);
</script>
```

3
content/authors.yml

@ -76,6 +76,9 @@ petehunt:
rachelnabors:
name: Rachel Nabors
url: https://twitter.com/rachelnabors
reactteam:
name: The React Team
url: https://reactjs.org/community/team.html
rickhanlonii:
name: Rick Hanlon
url: https://twitter.com/rickhanlonii

73
content/blog/2022-03-08-react-18-upgrade-guide.md

@ -1,29 +1,29 @@
---
title: "How to Upgrade to the React 18 Release Candidate"
title: "How to Upgrade to React 18"
author: [rickhanlonii]
---
Our next major version, React 18, is available today as a Release Candidate (RC). As we shared at [React Conf](https://reactjs.org/blog/2021/12/17/react-conf-2021-recap.html), React 18 introduces features powered by our new concurrent renderer, with a gradual adoption strategy for existing applications. In this post, we will guide you through the steps for upgrading to React 18.
As we shared in the [release post](/blog/2022/03/28/react-v18.html), React 18 introduces features powered by our new concurrent renderer, with a gradual adoption strategy for existing applications. In this post, we will guide you through the steps for upgrading to React 18.
If you'd like to help us test React 18, follow the steps in this upgrade guide and [report any issues](https://github.com/facebook/react/issues/new/choose) you encounter so we can fix them before the stable release.
Please [report any issues](https://github.com/facebook/react/issues/new/choose) you encounter while upgrading to React 18.
*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](https://www.youtube.com/watch?v=FZ0cG47msEk&t=1530s).*
## Installing
## Installing {#installing}
To install the latest React 18 RC, use the `@rc` tag:
To install the latest version of React:
```bash
npm install react@rc react-dom@rc
npm install react react-dom
```
Or if you’re using yarn:
```bash
yarn add react@rc react-dom@rc
yarn add react react-dom
```
## Updates to Client Rendering APIs
## Updates to Client Rendering APIs {#updates-to-client-rendering-apis}
When you first install React 18, you will see a warning in the console:
@ -97,7 +97,7 @@ const root = hydrateRoot(container, <App tab="home" />);
For more information, see the [working group discussion here](https://github.com/reactwg/react-18/discussions/5).
## Updates to Server Rendering APIs
## Updates to Server Rendering APIs {#updates-to-server-rendering-apis}
In this release, we’re revamping our `react-dom/server` APIs to fully support Suspense on the server and Streaming SSR. As part of these changes, we're deprecating the old Node streaming API, which does not support incremental Suspense streaming on the server.
@ -120,7 +120,7 @@ Finally, this API will continue to work for rendering e-mails:
For more information on the changes to server rendering APIs, see the working group post on [Upgrading to React 18 on the server](https://github.com/reactwg/react-18/discussions/22), a [deep dive on the new Suspense SSR Architecture](https://github.com/reactwg/react-18/discussions/37), and [Shaundai Person’s](https://twitter.com/shaundai) talk on [Streaming Server Rendering with Suspense](https://www.youtube.com/watch?v=pj5N-Khihgc) at React Conf 2021.
## Automatic Batching
## Automatic Batching {#automatic-batching}
React 18 adds out-of-the-box performance improvements by doing more batching by default. Batching is when React groups multiple state updates into a single re-render for better performance. Before React 18, 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:
@ -179,17 +179,16 @@ function handleClick() {
For more information, see the [Automatic batching deep dive](https://github.com/reactwg/react-18/discussions/21).
## New APIs for Libraries
## New APIs for Libraries {#new-apis-for-libraries}
In the React 18 Working Group we worked with library maintainers to create new APIs needed to support concurrent rendering for use cases specific to their use case in areas like styles, external stores, and accessibility. To support React 18, some libraries may need to switch to one of the following APIs:
In the React 18 Working Group we worked with library maintainers to create new APIs needed to support concurrent rendering for use cases specific to their use case in areas like styles, and external stores. To support React 18, some libraries may need to switch to one of the following APIs:
* `useId` is a new hook for generating unique IDs on both the client and server, while avoiding hydration mismatches. This solves an issue that already exists in React 17 and below, but it's even more important in React 18 because of how our streaming server renderer delivers HTML out-of-order. For more information see the [useId post in the working group](https://github.com/reactwg/react-18/discussions/111).
* `useSyncExternalStore` is a new hook that allows external stores to support concurrent reads by forcing updates to the store to be synchronous. This new API is recommended for any library that integrates with state external to React. For more information, see the [useSyncExternalStore overview post](https://github.com/reactwg/react-18/discussions/70) and [useSyncExternalStore API details](https://github.com/reactwg/react-18/discussions/86).
* `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. For more information, see the [Library Upgrade Guide for `<style>`](https://github.com/reactwg/react-18/discussions/110).
React 18 also introduces new APIs for concurrent rendering such as `startTransition` and `useDeferredValue`, which we will share more about in the upcoming stable release post.
React 18 also introduces new APIs for concurrent rendering such as `startTransition`, `useDeferredValue` and `useId`, which we share more about in the [release post](/blog/2022/03/28/react-v18.html).
## Updates to Strict Mode
## Updates to Strict Mode {#updates-to-strict-mode}
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.
@ -219,9 +218,9 @@ With Strict Mode in React 18, React will simulate unmounting and remounting the
* Effect setup code runs
```
For more information, see the Working Group posts for [Adding Strict Effects to Strict Mode](https://github.com/reactwg/react-18/discussions/19) and [How to Support Strict Effects](https://github.com/reactwg/react-18/discussions/18).
For more information, see the Working Group posts for [Adding Reusable State to StrictMode](https://github.com/reactwg/react-18/discussions/19) and [How to support Reusable State in Effects](https://github.com/reactwg/react-18/discussions/18).
## Configuring Your Testing Environment
## Configuring Your Testing Environment {#configuring-your-testing-environment}
When you first update your tests to use `createRoot`, you may see this warning in your test console:
@ -242,16 +241,42 @@ Eventually, we expect testing libraries will configure this for you automaticall
[More background on the the `act` testing API and related changes](https://github.com/reactwg/react-18/discussions/102) is available in the working group.
## Dropping Support for Internet Explorer
## Dropping Support for Internet Explorer {#dropping-support-for-internet-explorer}
In this release, React is dropping support for Internet Explorer, which is [going out of support on June 15, 2022](https://blogs.windows.com/windowsexperience/2021/05/19/the-future-of-internet-explorer-on-windows-10-is-in-microsoft-edge). We’re making this change now because new features introduced in React 18 are built using modern browser features such as microtasks which cannot be adequately polyfilled in IE.
If you need to support Internet Explorer we recommend you stay with React 17.
## Other Changes
## Deprecations {#deprecations}
* [Update to remove the "setState on unmounted component" warning](https://github.com/reactwg/react-18/discussions/82)
* [Suspense no longer requires a `fallback` prop to capture](https://github.com/reactwg/react-18/discussions/72)
* [Components can now render undefined](https://github.com/reactwg/react-18/discussions/75)
* [Deprecated renderSubtreeIntoContainer](https://github.com/facebook/react/pull/23355)
* [StrictMode updated to not silence double logging by default](https://github.com/reactwg/react-18/discussions/96)
* `react-dom`: `ReactDOM.render` has been deprecated. Using it will warn and run your app in React 17 mode.
* `react-dom`: `ReactDOM.hydrate` has been deprecated. Using it will warn and run your app in React 17 mode.
* `react-dom`: `ReactDOM.unmountComponentAtNode` has been deprecated.
* `react-dom`: `ReactDOM.renderSubtreeIntoContainer` has been deprecated.
* `react-dom/server`: `ReactDOMServer.renderToNodeStream` has been deprecated.
## Other Breaking Changes {#other-breaking-changes}
* **Consistent useEffect timing**: React now always synchronously flushes effect functions if the update was triggered during a discrete user input event such as a click or a keydown event. Previously, the behavior wasn't always predictable or consistent.
* **Stricter hydration errors**: Hydration mismatches due to missing or extra text content are now treated like errors instead of warnings. React will no longer attempt to "patch up" individual nodes by inserting or deleting a node on the client in an attempt to match the server markup, and will revert to client rendering up to the closest `<Suspense>` boundary in the tree. This ensures the hydrated tree is consistent and avoids potential privacy and security holes that can be caused by hydration mismatches.
* **Layout Effects with Suspense**: When a tree re-suspends and reverts to a fallback, React will now clean up layout effects, and then re-create them when the content inside the boundary is shown again. This fixes an issue which prevented component libraries from correctly measuring layout when used with Suspense.
* **New JS Environment Requirements**: React now depends on modern browsers features including `Promise`, `Symbol`, and `Object.assign`. If you support older browsers and devices such as Internet Explorer which do not provide modern browser features natively or have non-compliant implementations, consider including a global polyfill in your bundled application.
## Other Notable Changes {#other-notable-changes}
### React {#react}
* **Components can now render `undefined`:** React no longer warns if you return `undefined` from a component. This makes the allowed component return values consistent with values that are allowed in the middle of a component tree. We suggest to use a linter to prevent mistakes like forgetting a `return` statement before JSX.
* **In tests, `act` warnings are now opt-in:** If you're running end-to-end tests, the `act` warnings are unnecessary. We've introduced an [opt-in](https://github.com/reactwg/react-18/discussions/102) mechanism so you can enable them only for unit tests where they are useful and beneficial.
* **No warning about `setState` on unmounted components:** Previously, React warned about memory leaks when you call `setState` on an unmounted component. This warning was added for subscriptions, but people primarily run into it in scenarios where setting state is fine, and workarounds make the code worse. We've [removed](https://github.com/facebook/react/pull/22114) this warning.
* **No suppression of console logs:** When you use Strict Mode, React renders each component twice to help you find unexpected side effects. In React 17, we've suppressed console logs for one of the two renders to make the logs easier to read. In response to [community feedback](https://github.com/facebook/react/issues/21783) about this being confusing, we've removed the suppression. Instead, if you have React DevTools installed, the second log's renders will be displayed in grey, and there will be an option (off by default) to suppress them completely.
* **Improved memory usage:** React now cleans up more internal fields on unmount, making the impact from unfixed memory leaks that may exist in your application code less severe.
### React DOM Server {#react-dom-server}
* **`renderToString`:** Will no longer error when suspending on the server. Instead, it will emit the fallback HTML for the closest `<Suspense>` boundary and then retry rendering the same content on the client. It is still recommended that you switch to a streaming API like `renderToPipeableStream` or `renderToReadableStream` instead.
* **`renderToStaticMarkup`:** Will no longer error when suspending on the server. Instead, it will emit the fallback HTML for the closest `<Suspense>` boundary and retry rendering on the client.
## Changelog {#changelog}
You can view the [full changelog here](https://github.com/facebook/react/blob/main/CHANGELOG.md).

323
content/blog/2022-03-29-react-v18.md

@ -0,0 +1,323 @@
---
title: "React v18.0"
author: [reactteam]
---
React 18 is now available on npm!
In our last post, we shared step-by-step instructions for [upgrading your app to React 18](https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html). 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](https://reactjs.org/blog/2021/06/08/the-plan-for-react-18.html) 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](https://www.youtube.com/watch?v=FZ0cG47msEk&list=PLNG_1j3cPCaZZ7etkzWA7JfdmKWT0pMsa), we explain how React 18 fits into our mission to make it easy for developers to build great user experiences
* [Shruti Kapoor](https://twitter.com/shrutikapoor08) [demonstrated how to use the new features in React 18](https://www.youtube.com/watch?v=ytudH8je5ko&list=PLNG_1j3cPCaZZ7etkzWA7JfdmKWT0pMsa&index=2)
* [Shaundai Person](https://twitter.com/shaundai) gave us an overview of [streaming server rendering with Suspense](https://www.youtube.com/watch?v=pj5N-Khihgc&list=PLNG_1j3cPCaZZ7etkzWA7JfdmKWT0pMsa&index=3)
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](https://www.youtube.com/watch?v=FZ0cG47msEk&t=1530s).*
## What is Concurrent React? {#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 `<Offscreen>` 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 {#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 [`<StrictMode>`](/docs/strict-mode.html) 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](https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html).
## Suspense in Data Frameworks {#suspense-in-data-frameworks}
In React 18, you can start using Suspense for data fetching in opinionated frameworks like Relay, Next, 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 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-still-in-development}
[**Server Components**](https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html) 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, Hydrogen, and Remix to advance the proposal and get it ready for broad adoption.
## What's New in React 18 {#whats-new-in-react-18}
### New Feature: Automatic Batching {#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:
```js
// 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](https://github.com/reactwg/react-18/discussions/21).
### New Feature: Transitions {#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":
```js
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](https://github.com/reactjs/rfcs/blob/main/text/0213-suspense-in-react-18.md) for more info).
[See docs for transitions here](/docs/react-api.html#transitions).
### New Suspense Features {#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:
```js
<Suspense fallback={<Spinner />}>
<Comments />
</Suspense>
```
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](https://github.com/reactjs/rfcs/blob/main/text/0213-suspense-in-react-18.md).
### New Client and Server Rendering APIs {#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 {#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`](https://developer.mozilla.org/en-US/docs/Web/API/reportError), or `console.error` in the older browsers.
[See docs for React DOM Client here](/docs/react-dom-client.html).
#### React DOM Server {#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](/docs/react-dom-server.html).
### New Strict Mode Behaviors {#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](/docs/strict-mode.html#ensuring-reusable-state).
### New Hooks {#new-hooks}
#### useId {#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](/docs/hooks-reference.html#useid).
#### useTransition {#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](/docs/react-reference.html#transitions)
#### useDeferredValue {#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](/docs/hooks-reference.html#usedeferredvalue).
#### useSyncExternalStore {#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](/docs/hooks-reference.html#usesyncexternalstore).
> Note
>
> `useSyncExternalStore` is intended to be used by libraries, not application code.
#### useInsertionEffect {#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](/docs/hooks-reference.html#useinsertioneffect).
> Note
>
> `useInsertionEffect` is intended to be used by libraries, not application code.
## Changelog {#changelog}
### React {#react}
* Add `useTransition` and `useDeferredValue` to separate urgent updates from transitions. ([#10426](https://github.com/facebook/react/pull/10426), [#10715](https://github.com/facebook/react/pull/10715), [#15593](https://github.com/facebook/react/pull/15593), [#15272](https://github.com/facebook/react/pull/15272), [#15578](https://github.com/facebook/react/pull/15578), [#15769](https://github.com/facebook/react/pull/15769), [#17058](https://github.com/facebook/react/pull/17058), [#18796](https://github.com/facebook/react/pull/18796), [#19121](https://github.com/facebook/react/pull/19121), [#19703](https://github.com/facebook/react/pull/19703), [#19719](https://github.com/facebook/react/pull/19719), [#19724](https://github.com/facebook/react/pull/19724), [#20672](https://github.com/facebook/react/pull/20672), [#20976](https://github.com/facebook/react/pull/20976) by [@acdlite](https://github.com/acdlite), [@lunaruan](https://github.com/lunaruan), [@rickhanlonii](https://github.com/rickhanlonii), and [@sebmarkbage](https://github.com/sebmarkbage))
* Add `useId` for generating unique IDs. ([#17322](https://github.com/facebook/react/pull/17322), [#18576](https://github.com/facebook/react/pull/18576), [#22644](https://github.com/facebook/react/pull/22644), [#22672](https://github.com/facebook/react/pull/22672), [#21260](https://github.com/facebook/react/pull/21260) by [@acdlite](https://github.com/acdlite), [@lunaruan](https://github.com/lunaruan), and [@sebmarkbage](https://github.com/sebmarkbage))
* Add `useSyncExternalStore` to help external store libraries integrate with React. ([#15022](https://github.com/facebook/react/pull/15022), [#18000](https://github.com/facebook/react/pull/18000), [#18771](https://github.com/facebook/react/pull/18771), [#22211](https://github.com/facebook/react/pull/22211), [#22292](https://github.com/facebook/react/pull/22292), [#22239](https://github.com/facebook/react/pull/22239), [#22347](https://github.com/facebook/react/pull/22347), [#23150](https://github.com/facebook/react/pull/23150) by [@acdlite](https://github.com/acdlite), [@bvaughn](https://github.com/bvaughn), and [@drarmstr](https://github.com/drarmstr))
* Add `startTransition` as a version of `useTransition` without pending feedback. ([#19696](https://github.com/facebook/react/pull/19696) by [@rickhanlonii](https://github.com/rickhanlonii))
* Add `useInsertionEffect` for CSS-in-JS libraries. ([#21913](https://github.com/facebook/react/pull/21913) by [@rickhanlonii](https://github.com/rickhanlonii))
* Make Suspense remount layout effects when content reappears. ([#19322](https://github.com/facebook/react/pull/19322), [#19374](https://github.com/facebook/react/pull/19374), [#19523](https://github.com/facebook/react/pull/19523), [#20625](https://github.com/facebook/react/pull/20625), [#21079](https://github.com/facebook/react/pull/21079) by [@acdlite](https://github.com/acdlite), [@bvaughn](https://github.com/bvaughn), and [@lunaruan](https://github.com/lunaruan))
* Make `<StrictMode>` re-run effects to check for restorable state. ([#19523](https://github.com/facebook/react/pull/19523) , [#21418](https://github.com/facebook/react/pull/21418) by [@bvaughn](https://github.com/bvaughn) and [@lunaruan](https://github.com/lunaruan))
* Assume Symbols are always available. ([#23348](https://github.com/facebook/react/pull/23348) by [@sebmarkbage](https://github.com/sebmarkbage))
* Remove `object-assign` polyfill. ([#23351](https://github.com/facebook/react/pull/23351) by [@sebmarkbage](https://github.com/sebmarkbage))
* Remove unsupported `unstable_changedBits` API. ([#20953](https://github.com/facebook/react/pull/20953) by [@acdlite](https://github.com/acdlite))
* Allow components to render undefined. ([#21869](https://github.com/facebook/react/pull/21869) by [@rickhanlonii](https://github.com/rickhanlonii))
* Flush `useEffect` resulting from discrete events like clicks synchronously. ([#21150](https://github.com/facebook/react/pull/21150) by [@acdlite](https://github.com/acdlite))
* Suspense `fallback={undefined}` now behaves the same as `null` and isn't ignored. ([#21854](https://github.com/facebook/react/pull/21854) by [@rickhanlonii](https://github.com/rickhanlonii))
* Consider all `lazy()` resolving to the same component equivalent. ([#20357](https://github.com/facebook/react/pull/20357) by [@sebmarkbage](https://github.com/sebmarkbage))
* Don't patch console during first render. ([#22308](https://github.com/facebook/react/pull/22308) by [@lunaruan](https://github.com/lunaruan))
* Improve memory usage. ([#21039](https://github.com/facebook/react/pull/21039) by [@bgirard](https://github.com/bgirard))
* Improve messages if string coercion throws (Temporal.*, Symbol, etc.) ([#22064](https://github.com/facebook/react/pull/22064) by [@justingrant](https://github.com/justingrant))
* Use `setImmediate` when available over `MessageChannel`. ([#20834](https://github.com/facebook/react/pull/20834) by [@gaearon](https://github.com/gaearon))
* Fix context failing to propagate inside suspended trees. ([#23095](https://github.com/facebook/react/pull/23095) by [@gaearon](https://github.com/gaearon))
* Fix `useReducer` observing incorrect props by removing the eager bailout mechanism. ([#22445](https://github.com/facebook/react/pull/22445) by [@josephsavona](https://github.com/josephsavona))
* Fix `setState` being ignored in Safari when appending iframes. ([#23111](https://github.com/facebook/react/pull/23111) by [@gaearon](https://github.com/gaearon))
* Fix a crash when rendering `ZonedDateTime` in the tree. ([#20617](https://github.com/facebook/react/pull/20617) by [@dimaqq](https://github.com/dimaqq))
* Fix a crash when document is set to `null` in tests. ([#22695](https://github.com/facebook/react/pull/22695) by [@SimenB](https://github.com/SimenB))
* Fix `onLoad` not triggering when concurrent features are on. ([#23316](https://github.com/facebook/react/pull/23316) by [@gnoff](https://github.com/gnoff))
* Fix a warning when a selector returns `NaN`. ([#23333](https://github.com/facebook/react/pull/23333) by [@hachibeeDI](https://github.com/hachibeeDI))
* Fix a crash when document is set to `null` in tests. ([#22695](https://github.com/facebook/react/pull/22695) by [@SimenB](https://github.com/SimenB))
* Fix the generated license header. ([#23004](https://github.com/facebook/react/pull/23004) by [@vitaliemiron](https://github.com/vitaliemiron))
* Add `package.json` as one of the entry points. ([#22954](https://github.com/facebook/react/pull/22954) by [@Jack](https://github.com/Jack-Works))
* Allow suspending outside a Suspense boundary. ([#23267](https://github.com/facebook/react/pull/23267) by [@acdlite](https://github.com/acdlite))
* Log a recoverable error whenever hydration fails. ([#23319](https://github.com/facebook/react/pull/23319) by [@acdlite](https://github.com/acdlite))
### React DOM {#react-dom}
* Add `createRoot` and `hydrateRoot`. ([#10239](https://github.com/facebook/react/pull/10239), [#11225](https://github.com/facebook/react/pull/11225), [#12117](https://github.com/facebook/react/pull/12117), [#13732](https://github.com/facebook/react/pull/13732), [#15502](https://github.com/facebook/react/pull/15502), [#15532](https://github.com/facebook/react/pull/15532), [#17035](https://github.com/facebook/react/pull/17035), [#17165](https://github.com/facebook/react/pull/17165), [#20669](https://github.com/facebook/react/pull/20669), [#20748](https://github.com/facebook/react/pull/20748), [#20888](https://github.com/facebook/react/pull/20888), [#21072](https://github.com/facebook/react/pull/21072), [#21417](https://github.com/facebook/react/pull/21417), [#21652](https://github.com/facebook/react/pull/21652), [#21687](https://github.com/facebook/react/pull/21687), [#23207](https://github.com/facebook/react/pull/23207), [#23385](https://github.com/facebook/react/pull/23385) by [@acdlite](https://github.com/acdlite), [@bvaughn](https://github.com/bvaughn), [@gaearon](https://github.com/gaearon), [@lunaruan](https://github.com/lunaruan), [@rickhanlonii](https://github.com/rickhanlonii), [@trueadm](https://github.com/trueadm), and [@sebmarkbage](https://github.com/sebmarkbage))
* Add selective hydration. ([#14717](https://github.com/facebook/react/pull/14717), [#14884](https://github.com/facebook/react/pull/14884), [#16725](https://github.com/facebook/react/pull/16725), [#16880](https://github.com/facebook/react/pull/16880), [#17004](https://github.com/facebook/react/pull/17004), [#22416](https://github.com/facebook/react/pull/22416), [#22629](https://github.com/facebook/react/pull/22629), [#22448](https://github.com/facebook/react/pull/22448), [#22856](https://github.com/facebook/react/pull/22856), [#23176](https://github.com/facebook/react/pull/23176) by [@acdlite](https://github.com/acdlite), [@gaearon](https://github.com/gaearon), [@salazarm](https://github.com/salazarm), and [@sebmarkbage](https://github.com/sebmarkbage))
* Add `aria-description` to the list of known ARIA attributes. ([#22142](https://github.com/facebook/react/pull/22142) by [@mahyareb](https://github.com/mahyareb))
* Add `onResize` event to video elements. ([#21973](https://github.com/facebook/react/pull/21973) by [@rileyjshaw](https://github.com/rileyjshaw))
* Add `imageSizes` and `imageSrcSet` to known props. ([#22550](https://github.com/facebook/react/pull/22550) by [@eps1lon](https://github.com/eps1lon))
* Allow non-string `<option>` children if `value` is provided. ([#21431](https://github.com/facebook/react/pull/21431) by [@sebmarkbage](https://github.com/sebmarkbage))
* Fix `aspectRatio` style not being applied. ([#21100](https://github.com/facebook/react/pull/21100) by [@gaearon](https://github.com/gaearon))
* Warn if `renderSubtreeIntoContainer` is called. ([#23355](https://github.com/facebook/react/pull/23355) by [@acdlite](https://github.com/acdlite))
### React DOM Server {#react-dom-server-1}
* Add the new streaming renderer. ([#14144](https://github.com/facebook/react/pull/14144), [#20970](https://github.com/facebook/react/pull/20970), [#21056](https://github.com/facebook/react/pull/21056), [#21255](https://github.com/facebook/react/pull/21255), [#21200](https://github.com/facebook/react/pull/21200), [#21257](https://github.com/facebook/react/pull/21257), [#21276](https://github.com/facebook/react/pull/21276), [#22443](https://github.com/facebook/react/pull/22443), [#22450](https://github.com/facebook/react/pull/22450), [#23247](https://github.com/facebook/react/pull/23247), [#24025](https://github.com/facebook/react/pull/24025), [#24030](https://github.com/facebook/react/pull/24030) by [@sebmarkbage](https://github.com/sebmarkbage))
* Fix context providers in SSR when handling multiple requests. ([#23171](https://github.com/facebook/react/pull/23171) by [@frandiox](https://github.com/frandiox))
* Revert to client render on text mismatch. ([#23354](https://github.com/facebook/react/pull/23354) by [@acdlite](https://github.com/acdlite))
* Deprecate `renderToNodeStream`. ([#23359](https://github.com/facebook/react/pull/23359) by [@sebmarkbage](https://github.com/sebmarkbage))
* Fix a spurious error log in the new server renderer. ([#24043](https://github.com/facebook/react/pull/24043) by [@eps1lon](https://github.com/eps1lon))
* Fix a bug in the new server renderer. ([#22617](https://github.com/facebook/react/pull/22617) by [@shuding](https://github.com/shuding))
* Ignore function and symbol values inside custom elements on the server. ([#21157](https://github.com/facebook/react/pull/21157) by [@sebmarkbage](https://github.com/sebmarkbage))
### React DOM Test Utils {#react-dom-test-utils}
* Throw when `act` is used in production. ([#21686](https://github.com/facebook/react/pull/21686) by [@acdlite](https://github.com/acdlite))
* Support disabling spurious act warnings with `global.IS_REACT_ACT_ENVIRONMENT`. ([#22561](https://github.com/facebook/react/pull/22561) by [@acdlite](https://github.com/acdlite))
* Expand act warning to cover all APIs that might schedule React work. ([#22607](https://github.com/facebook/react/pull/22607) by [@acdlite](https://github.com/acdlite))
* Make `act` batch updates. ([#21797](https://github.com/facebook/react/pull/21797) by [@acdlite](https://github.com/acdlite))
* Remove warning for dangling passive effects. ([#22609](https://github.com/facebook/react/pull/22609) by [@acdlite](https://github.com/acdlite))
### React Refresh {#react-refresh}
* Track late-mounted roots in Fast Refresh. ([#22740](https://github.com/facebook/react/pull/22740) by [@anc95](https://github.com/anc95))
* Add `exports` field to `package.json`. ([#23087](https://github.com/facebook/react/pull/23087) by [@otakustay](https://github.com/otakustay))
### Server Components (Experimental) {#server-components-experimental}
* Add Server Context support. ([#23244](https://github.com/facebook/react/pull/22739) by [@salazarm](https://github.com/salazarm))
* Add `lazy` support. ([#24068](https://github.com/facebook/react/pull/24068) by [@gnoff](https://github.com/gnoff))
* Update webpack plugin for webpack 5 ([#22739](https://github.com/facebook/react/pull/22739) by [@michenly](https://github.com/michenly))
* Fix a mistake in the Node loader. ([#22537](https://github.com/facebook/react/pull/22537) by [@btea](https://github.com/btea))
* Use `globalThis` instead of `window` for edge environments. ([#22777](https://github.com/facebook/react/pull/22777) by [@huozhi](https://github.com/huozhi))

2
content/community/conferences.md

@ -46,7 +46,7 @@ June 17 & 21, 2022. In-person in Amsterdam, Netherlands + remote first interacti
[Website](https://reactsummit.com) - [Twitter](https://twitter.com/reactsummit) - [Facebook](https://www.facebook.com/reactamsterdam) - [Videos](https://youtube.com/c/ReactConferences)
### React Native EU 2022: Powered by {callstack}
### React Native EU 2022: Powered by {callstack} {#react-native-eu-2022-powered-by-callstack}
September 1-2, 2022 - Remote event
[Website](https://www.react-native.eu/?utm_campaign=React_Native_EU&utm_source=referral&utm_content=reactjs_community_conferences) -

7
content/docs/add-react-to-a-website.md

@ -77,14 +77,15 @@ Open **[this starter code](https://gist.github.com/gaearon/0b180827c190fe4fd98b4
After **[the starter code](https://gist.github.com/gaearon/0b180827c190fe4fd98b4c7f570ea4a8/raw/b9157ce933c79a4559d2aa9ff3372668cce48de7/LikeButton.js)**, add two lines to the bottom of `like_button.js`:
```js{3,4}
```js{3,4,5}
// ... the starter code you pasted ...
const domContainer = document.querySelector('#like_button_container');
ReactDOM.render(e(LikeButton), domContainer);
const root = ReactDOM.createRoot(domContainer);
root.render(e(LikeButton));
```
These two lines of code find the `<div>` we added to our HTML in the first step, and then display our "Like" button React component inside of it.
These three lines of code find the `<div>` we added to our HTML in the first step, create a React app with it, and then display our "Like" button React component inside of it.
### That's It! {#thats-it}

2
content/docs/addons-shallow-renderer.md

@ -59,7 +59,7 @@ Shallow testing currently has some limitations, namely not supporting refs.
You can think of the shallowRenderer as a "place" to render the component you're testing, and from which you can extract the component's output.
`shallowRenderer.render()` is similar to [`ReactDOM.render()`](/docs/react-dom.html#render) but it doesn't require DOM and only renders a single level deep. This means you can test components isolated from how their children are implemented.
`shallowRenderer.render()` is similar to [`root.render()`](/docs/react-dom-client.html#createroot) but it doesn't require DOM and only renders a single level deep. This means you can test components isolated from how their children are implemented.
### `shallowRenderer.getRenderOutput()` {#shallowrenderergetrenderoutput}

6
content/docs/addons-test-utils.md

@ -89,7 +89,7 @@ Here is how we can test it:
```js{3,20-22,29-31}
import React from 'react';
import ReactDOM from 'react-dom';
import ReactDOM from 'react-dom/client';
import { act } from 'react-dom/test-utils';
import Counter from './Counter';
@ -108,7 +108,7 @@ afterEach(() => {
it('can render and update a counter', () => {
// Test first render and componentDidMount
act(() => {
ReactDOM.render(<Counter />, container);
ReactDOM.createRoot(container).render(<Counter />);
});
const button = container.querySelector('button');
const label = container.querySelector('p');
@ -304,7 +304,7 @@ Render a React element into a detached DOM node in the document. **This function
```js
const domContainer = document.createElement('div');
ReactDOM.render(element, domContainer);
ReactDOM.createRoot(domContainer).render(element);
```
> Note:

50
content/docs/code-splitting.md

@ -81,10 +81,6 @@ When using [Babel](https://babeljs.io/), you'll need to make sure that Babel can
## `React.lazy` {#reactlazy}
> Note:
>
> `React.lazy` and Suspense are not yet available for server-side rendering. If you want to do code-splitting in a server rendered app, we recommend [Loadable Components](https://github.com/gregberge/loadable-components). It has a nice [guide for bundle splitting with server-side rendering](https://loadable-components.com/docs/server-side-rendering/).
The `React.lazy` function lets you render a dynamic import as a regular component.
**Before:**
@ -143,6 +139,52 @@ function MyComponent() {
}
```
### Avoiding fallbacks {#avoiding-fallbacks}
Any component may suspend as a result of rendering, even components that were already shown to the user. In order for screen content to always be consistent, if an already shown component suspends, React has to hide its tree up to the closest `<Suspense>` boundary. However, from the user's perspective, this can be disorienting.
Consider this tab switcher:
```js
import React, { Suspense } from 'react';
import Tabs from './Tabs';
import Glimmer from './Glimmer';
const Comments = React.lazy(() => import('./Comments'));
const Photos = React.lazy(() => import('./Photos'));
function MyComponent() {
const [tab, setTab] = React.useState('photos');
function handleTabSelect(tab) {
setTab(tab);
};
return (
<div>
<Tabs onTabSelect={handleTabSelect} />
<Suspense fallback={<Glimmer />}>
{tab === 'photos' ? <Photos /> : <Comments />}
</Suspense>
</div>
);
}
```
In this example, if tab gets changed from `'photos'` to `'comments'`, but `Comments` suspends, the user will see a glimmer. This makes sense because the user no longer wants to see `Photos`, the `Comments` component is not ready to render anything, and React needs to keep the user experience consistent, so it has no choice but to show the `Glimmer` above.
However, sometimes this user experience is not desirable. In particular, it is sometimes better to show the "old" UI while the new UI is being prepared. You can use the new [`startTransition`](/docs/react-api.html#starttransition) API to make React do this:
```js
function handleTabSelect(tab) {
startTransition(() => {
setTab(tab);
});
}
```
Here, you tell React that setting tab to `'comments'` is not an urgent update, but is a [transition](/docs/react-api.html#transitions) that may take some time. React will then keep the old UI in place and interactive, and will switch to showing `<Comments />` when it is ready. See [Transitions](/docs/react-api.html#transitions) for more info.
### Error boundaries {#error-boundaries}
If the other module fails to load (for example, due to network failure), it will trigger an error. You can handle these errors to show a nice user experience and manage recovery with [Error Boundaries](/docs/error-boundaries.html). Once you've created your Error Boundary, you can use it anywhere above your lazy components to display an error state when there's a network error.

13
content/docs/components-and-props.md

@ -70,17 +70,15 @@ function Welcome(props) {
}
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(element);
```
**[Try it on CodePen](https://codepen.io/gaearon/pen/YGYmEG?editors=1010)**
Let's recap what happens in this example:
1. We call `ReactDOM.render()` with the `<Welcome name="Sara" />` element.
1. We call `root.render()` with the `<Welcome name="Sara" />` element.
2. React calls the `Welcome` component with `{name: 'Sara'}` as the props.
3. Our `Welcome` component returns a `<h1>Hello, Sara</h1>` element as the result.
4. React DOM efficiently updates the DOM to match `<h1>Hello, Sara</h1>`.
@ -111,11 +109,6 @@ function App() {
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
```
**[Try it on CodePen](https://codepen.io/gaearon/pen/KgQKPr?editors=1010)**

144
content/docs/concurrent-mode-adoption.md

@ -1,144 +0,0 @@
---
id: concurrent-mode-adoption
title: Adopting Concurrent Mode (Experimental)
permalink: docs/concurrent-mode-adoption.html
prev: concurrent-mode-patterns.html
next: concurrent-mode-reference.html
---
<style>
.scary > blockquote {
background-color: rgba(237, 51, 21, 0.2);
border-left-color: #ed3315;
}
</style>
<div class="scary">
>Caution:
>
>This page was about experimental features that aren't yet available in a stable release. It was aimed at early adopters and people who are curious.
>
>Much of the information on this page is now outdated and exists only for archival purposes. **Please refer to the [React 18 Alpha announcement post](/blog/2021/06/08/the-plan-for-react-18.html
) for the up-to-date information.**
>
>Before React 18 is released, we will replace this page with stable documentation.
</div>
- [Installation](#installation)
- [Who Is This Experimental Release For?](#who-is-this-experimental-release-for)
- [Enabling Concurrent Mode](#enabling-concurrent-mode)
- [What to Expect](#what-to-expect)
- [Migration Step: Blocking Mode](#migration-step-blocking-mode)
- [Why So Many Modes?](#why-so-many-modes)
- [Feature Comparison](#feature-comparison)
## Installation {#installation}
Concurrent Mode is only available in the [experimental builds](/blog/2019/10/22/react-release-channels.html#experimental-channel) of React. To install them, run:
```
npm install react@experimental react-dom@experimental
```
**There are no semantic versioning guarantees for the experimental builds.**
APIs may be added, changed, or removed with any `@experimental` release.
**Experimental releases will have frequent breaking changes.**
You can try these builds on personal projects or in a branch, but we don't recommend running them in production. At Facebook, we *do* run them in production, but that's because we're also there to fix bugs when something breaks. You've been warned!
### Who Is This Experimental Release For? {#who-is-this-experimental-release-for}
This release is primarily aimed at early adopters, library authors, and curious people.
We're using this code in production (and it works for us) but there are still some bugs, missing features, and gaps in the documentation. We'd like to hear more about what breaks in Concurrent Mode so we can better prepare it for an official stable release in the future.
### Enabling Concurrent Mode {#enabling-concurrent-mode}
Normally, when we add features to React, you can start using them immediately. Fragments, Context, and even Hooks are examples of such features. You can use them in new code without making any changes to the existing code.
Concurrent Mode is different. It introduces semantic changes to how React works. Otherwise, the [new features](/docs/concurrent-mode-patterns.html) enabled by it *wouldn't be possible*. This is why they're grouped into a new "mode" rather than released one by one in isolation.
You can't opt into Concurrent Mode on a per-subtree basis. Instead, to opt in, you have to do it in the place where today you call `ReactDOM.render()`.
**This will enable Concurrent Mode for the whole `<App />` tree:**
```js
import ReactDOM from 'react-dom';
// If you previously had:
//
// ReactDOM.render(<App />, document.getElementById('root'));
//
// You can opt into Concurrent Mode by writing:
ReactDOM.unstable_createRoot(
document.getElementById('root')
).render(<App />);
```
>Note:
>
>Concurrent Mode APIs such as `createRoot` only exist in the experimental builds of React.
In Concurrent Mode, the lifecycle methods [previously marked](/blog/2018/03/27/update-on-async-rendering.html) as "unsafe" actually *are* unsafe, and lead to bugs even more than in today's React. We don't recommend trying Concurrent Mode until your app is [Strict Mode](/docs/strict-mode.html)-compatible.
## What to Expect {#what-to-expect}
If you have a large existing app, or if your app depends on a lot of third-party packages, please don't expect that you can use the Concurrent Mode immediately. **For example, at Facebook we are using Concurrent Mode for the new website, but we're not planning to enable it on the old website.** This is because our old website still uses unsafe lifecycle methods in the product code, incompatible third-party libraries, and patterns that don't work well with the Concurrent Mode.
In our experience, code that uses idiomatic React patterns and doesn't rely on external state management solutions is the easiest to get running in the Concurrent Mode. We will describe common problems we've seen and the solutions to them separately in the coming weeks.
### Migration Step: Blocking Mode {#migration-step-blocking-mode}
For older codebases, Concurrent Mode might be a step too far. This is why we also provide a new "Blocking Mode" in the experimental React builds. You can try it by substituting `createRoot` with `createBlockingRoot`. It only offers a *small subset* of the Concurrent Mode features, but it is closer to how React works today and can serve as a migration step.
To recap:
* **Legacy Mode:** `ReactDOM.render(<App />, rootNode)`. This is what React apps use today. There are no plans to remove the legacy mode in the observable future — but it won't be able to support these new features.
* **Blocking Mode:** `ReactDOM.createBlockingRoot(rootNode).render(<App />)`. It is currently experimental. It is intended as a first migration step for apps that want to get a subset of Concurrent Mode features.
* **Concurrent Mode:** `ReactDOM.createRoot(rootNode).render(<App />)`. It is currently experimental. In the future, after it stabilizes, we intend to make it the default React mode. This mode enables *all* the new features.
### Why So Many Modes? {#why-so-many-modes}
We think it is better to offer a [gradual migration strategy](/docs/faq-versioning.html#commitment-to-stability) than to make huge breaking changes — or to let React stagnate into irrelevance.
In practice, we expect that most apps using Legacy Mode today should be able to migrate at least to the Blocking Mode (if not Concurrent Mode). This fragmentation can be annoying for libraries that aim to support all Modes in the short term. However, gradually moving the ecosystem away from the Legacy Mode will also *solve* problems that affect major libraries in the React ecosystem, such as [confusing Suspense behavior when reading layout](https://github.com/facebook/react/issues/14536) and [lack of consistent batching guarantees](https://github.com/facebook/react/issues/15080). There's a number of bugs that can't be fixed in Legacy Mode without changing semantics, but don't exist in Blocking and Concurrent Modes.
You can think of the Blocking Mode as a "gracefully degraded" version of the Concurrent Mode. **As a result, in longer term we should be able to converge and stop thinking about different Modes altogether.** But for now, Modes are an important migration strategy. They let everyone decide when a migration is worth it, and upgrade at their own pace.
### Feature Comparison {#feature-comparison}
<style>
#feature-table table { border-collapse: collapse; }
#feature-table th { padding-right: 30px; }
#feature-table tr { border-bottom: 1px solid #eee; }
</style>
<div id="feature-table">
| |Legacy Mode |Blocking Mode |Concurrent Mode |
|--- |--- |--- |--- |
|[String Refs](/docs/refs-and-the-dom.html#legacy-api-string-refs) |✅ |🚫** |🚫** |
|[Legacy Context](/docs/legacy-context.html) |✅ |🚫** |🚫** |
|[findDOMNode](/docs/strict-mode.html#warning-about-deprecated-finddomnode-usage) |✅ |🚫** |🚫** |
|[Suspense](/docs/concurrent-mode-suspense.html#what-is-suspense-exactly) |✅ |✅ |✅ |
|[SuspenseList](/docs/concurrent-mode-patterns.html#suspenselist) |🚫 |✅ |✅ |
|Suspense SSR + Hydration |🚫 |✅ |✅ |
|Progressive Hydration |🚫 |✅ |✅ |
|Selective Hydration |🚫 |🚫 |✅ |
|Cooperative Multitasking |🚫 |🚫 |✅ |
|Automatic batching of multiple setStates    |🚫* |✅ |✅ |
|[Priority-based Rendering](/docs/concurrent-mode-patterns.html#splitting-high-and-low-priority-state) |🚫 |🚫 |✅ |
|[Interruptible Prerendering](/docs/concurrent-mode-intro.html#interruptible-rendering) |🚫 |🚫 |✅ |
|[useTransition](/docs/concurrent-mode-patterns.html#transitions) |🚫 |🚫 |✅ |
|[useDeferredValue](/docs/concurrent-mode-patterns.html#deferring-a-value) |🚫 |🚫 |✅ |
|[Suspense Reveal "Train"](/docs/concurrent-mode-patterns.html#suspense-reveal-train) |🚫 |🚫 |✅ |
</div>
\*: Legacy mode has automatic batching in React-managed events but it's limited to one browser task. Non-React events must opt-in using `unstable_batchedUpdates`. In Blocking Mode and Concurrent Mode, all `setState`s are batched by default.
\*\*: Warns in development.

103
content/docs/concurrent-mode-intro.md

@ -1,103 +0,0 @@
---
id: concurrent-mode-intro
title: Introducing Concurrent Mode (Experimental)
permalink: docs/concurrent-mode-intro.html
next: concurrent-mode-suspense.html
---
<style>
.scary > blockquote {
background-color: rgba(237, 51, 21, 0.2);
border-left-color: #ed3315;
}
</style>
<div class="scary">
>Caution:
>
>This page was about experimental features that aren't yet available in a stable release. It was aimed at early adopters and people who are curious.
>
>Much of the information on this page is now outdated and exists only for archival purposes. **Please refer to the [React 18 Alpha announcement post](/blog/2021/06/08/the-plan-for-react-18.html
) for the up-to-date information.**
>
>Before React 18 is released, we will replace this page with stable documentation.
</div>
This page provides a theoretical overview of Concurrent Mode. **For a more practical introduction, you might want to check out the next sections:**
* [Suspense for Data Fetching](/docs/concurrent-mode-suspense.html) describes a new mechanism for fetching data in React components.
* [Concurrent UI Patterns](/docs/concurrent-mode-patterns.html) shows some UI patterns made possible by Concurrent Mode and Suspense.
* [Adopting Concurrent Mode](/docs/concurrent-mode-adoption.html) explains how you can try Concurrent Mode in your project.
* [Concurrent Mode API Reference](/docs/concurrent-mode-reference.html) documents the new APIs available in experimental builds.
## What Is Concurrent Mode? {#what-is-concurrent-mode}
Concurrent Mode is a set of new features that help React apps stay responsive and gracefully adjust to the user's device capabilities and network speed.
These features are still experimental and are subject to change. They are not yet a part of a stable React release, but you can try them in an experimental build.
## Blocking vs Interruptible Rendering {#blocking-vs-interruptible-rendering}
**To explain Concurrent Mode, we'll use version control as a metaphor.** If you work on a team, you probably use a version control system like Git and work on branches. When a branch is ready, you can merge your work into main so that other people can pull it.
Before version control existed, the development workflow was very different. There was no concept of branches. If you wanted to edit some files, you had to tell everyone not to touch those files until you've finished your work. You couldn't even start working on them concurrently with that person — you were literally *blocked* by them.
This illustrates how UI libraries, including React, typically work today. Once they start rendering an update, including creating new DOM nodes and running the code inside components, they can't interrupt this work. We'll call this approach "blocking rendering".
In Concurrent Mode, rendering is not blocking. It is interruptible. This improves the user experience. It also unlocks new features that weren't possible before. Before we look at concrete examples in the [next](/docs/concurrent-mode-suspense.html) [chapters](/docs/concurrent-mode-patterns.html), we'll do a high-level overview of new features.
### Interruptible Rendering {#interruptible-rendering}
Consider a filterable product list. Have you ever typed into a list filter and felt that it stutters on every key press? Some of the work to update the product list might be unavoidable, such as creating new DOM nodes or the browser performing layout. However, *when* and *how* we perform that work plays a big role.
A common way to work around the stutter is to "debounce" the input. When debouncing, we only update the list *after* the user stops typing. However, it can be frustrating that the UI doesn't update while we're typing. As an alternative, we could "throttle" the input, and update the list with a certain maximum frequency. But then on lower-powered devices we'd still end up with stutter. Both debouncing and throttling create a suboptimal user experience.
The reason for the stutter is simple: once rendering begins, it can't be interrupted. So the browser can't update the text input right after the key press. No matter how good a UI library (such as React) might look on a benchmark, if it uses blocking rendering, a certain amount of work in your components will always cause stutter. And, often, there is no easy fix.
**Concurrent Mode fixes this fundamental limitation by making rendering interruptible.** This means when the user presses another key, React doesn't need to block the browser from updating the text input. Instead, it can let the browser paint an update to the input, and then continue rendering the updated list *in memory*. When the rendering is finished, React updates the DOM, and changes are reflected on the screen.
Conceptually, you can think of this as React preparing every update "on a branch". Just like you can abandon work in branches or switch between them, React in Concurrent Mode can interrupt an ongoing update to do something more important, and then come back to what it was doing earlier. This technique might also remind you of [double buffering](https://wiki.osdev.org/Double_Buffering) in video games.
Concurrent Mode techniques reduce the need for debouncing and throttling in UI. Because rendering is interruptible, React doesn't need to artificially *delay* work to avoid stutter. It can start rendering right away, but interrupt this work when needed to keep the app responsive.
### Intentional Loading Sequences {#intentional-loading-sequences}
We've said before that Concurrent Mode is like React working "on a branch". Branches are useful not only for short-term fixes, but also for long-running features. Sometimes you might work on a feature, but it could take weeks before it's in a "good enough state" to merge into main. This side of our version control metaphor applies to rendering too.
Imagine we're navigating between two screens in an app. Sometimes, we might not have enough code and data loaded to show a "good enough" loading state to the user on the new screen. Transitioning to an empty screen or a large spinner can be a jarring experience. However, it's also common that the necessary code and data doesn't take too long to fetch. **Wouldn't it be nicer if React could stay on the old screen for a little longer, and "skip" the "bad loading state" before showing the new screen?**
While this is possible today, it can be difficult to orchestrate. In Concurrent Mode, this feature is built-in. React starts preparing the new screen in memory first — or, as our metaphor goes, "on a different branch". So React can wait before updating the DOM so that more content can load. In Concurrent Mode, we can tell React to keep showing the old screen, fully interactive, with an inline loading indicator. And when the new screen is ready, React can take us to it.
### Concurrency {#concurrency}
Let's recap the two examples above and see how Concurrent Mode unifies them. **In Concurrent Mode, React can work on several state updates *concurrently*** — just like branches let different team members work independently:
* For CPU-bound updates (such as creating DOM nodes and running component code), concurrency means that a more urgent update can "interrupt" rendering that has already started.
* For IO-bound updates (such as fetching code or data from the network), concurrency means that React can start rendering in memory even before all the data arrives, and skip showing jarring empty loading states.
Importantly, the way you *use* React is the same. Concepts like components, props, and state fundamentally work the same way. When you want to update the screen, you set the state.
React uses a heuristic to decide how "urgent" an update is, and lets you adjust it with a few lines of code so that you can achieve the desired user experience for every interaction.
## Putting Research into Production {#putting-research-into-production}
There is a common theme around Concurrent Mode features. **Its mission is to help integrate the findings from the Human-Computer Interaction research into real UIs.**
For example, research shows that displaying too many intermediate loading states when transitioning between screens makes a transition feel *slower*. This is why Concurrent Mode shows new loading states on a fixed "schedule" to avoid jarring and too frequent updates.
Similarly, we know from research that interactions like hover and text input need to be handled within a very short period of time, while clicks and page transitions can wait a little longer without feeling laggy. The different "priorities" that Concurrent Mode uses internally roughly correspond to the interaction categories in the human perception research.
Teams with a strong focus on user experience sometimes solve similar problems with one-off solutions. However, those solutions rarely survive for a long time, as they're hard to maintain. With Concurrent Mode, our goal is to bake the UI research findings into the abstraction itself, and provide idiomatic ways to use them. As a UI library, React is well-positioned to do that.
## Next Steps {#next-steps}
Now you know what Concurrent Mode is all about!
On the next pages, you'll learn more details about specific topics:
* [Suspense for Data Fetching](/docs/concurrent-mode-suspense.html) describes a new mechanism for fetching data in React components.
* [Concurrent UI Patterns](/docs/concurrent-mode-patterns.html) shows some UI patterns made possible by Concurrent Mode and Suspense.
* [Adopting Concurrent Mode](/docs/concurrent-mode-adoption.html) explains how you can try Concurrent Mode in your project.
* [Concurrent Mode API Reference](/docs/concurrent-mode-reference.html) documents the new APIs available in experimental builds.

940
content/docs/concurrent-mode-patterns.md

@ -1,940 +0,0 @@
---
id: concurrent-mode-patterns
title: Concurrent UI Patterns (Experimental)
permalink: docs/concurrent-mode-patterns.html
prev: concurrent-mode-suspense.html
next: concurrent-mode-adoption.html
---
<style>
.scary > blockquote {
background-color: rgba(237, 51, 21, 0.2);
border-left-color: #ed3315;
}
</style>
<div class="scary">
>Caution:
>
>This page was about experimental features that aren't yet available in a stable release. It was aimed at early adopters and people who are curious.
>
>Much of the information on this page is now outdated and exists only for archival purposes. **Please refer to the [React 18 Alpha announcement post](/blog/2021/06/08/the-plan-for-react-18.html
) for the up-to-date information.**
>
>Before React 18 is released, we will replace this page with stable documentation.
</div>
Usually, when we update the state, we expect to see changes on the screen immediately. This makes sense because we want to keep our app responsive to user input. However, there are cases where we might prefer to **defer an update from appearing on the screen**.
For example, if we switch from one page to another, and none of the code or data for the next screen has loaded yet, it might be frustrating to immediately see a blank page with a loading indicator. We might prefer to stay longer on the previous screen. Implementing this pattern has historically been difficult in React. Concurrent Mode offers a new set of tools to do that.
- [Transitions](#transitions)
- [Wrapping setState in a Transition](#wrapping-setstate-in-a-transition)
- [Adding a Pending Indicator](#adding-a-pending-indicator)
- [Reviewing the Changes](#reviewing-the-changes)
- [Where Does the Update Happen?](#where-does-the-update-happen)
- [Transitions Are Everywhere](#transitions-are-everywhere)
- [Baking Transitions Into the Design System](#baking-transitions-into-the-design-system)
- [The Three Steps](#the-three-steps)
- [Default: Receded → Skeleton → Complete](#default-receded-skeleton-complete)
- [Preferred: Pending → Skeleton → Complete](#preferred-pending-skeleton-complete)
- [Wrap Lazy Features in `<Suspense>`](#wrap-lazy-features-in-suspense)
- [Suspense Reveal “Train”](#suspense-reveal-train)
- [Delaying a Pending Indicator](#delaying-a-pending-indicator)
- [Recap](#recap)
- [Other Patterns](#other-patterns)
- [Splitting High and Low Priority State](#splitting-high-and-low-priority-state)
- [Deferring a Value](#deferring-a-value)
- [SuspenseList](#suspenselist)
- [Next Steps](#next-steps)
## Transitions {#transitions}
Let's revisit [this demo](https://codesandbox.io/s/sparkling-field-41z4r3) from the previous page about [Suspense for Data Fetching](/docs/concurrent-mode-suspense.html).
When we click the "Next" button to switch the active profile, the existing page data immediately disappears, and we see the loading indicator for the whole page again. We can call this an "undesirable" loading state. **It would be nice if we could "skip" it and wait for some content to load before transitioning to the new screen.**
React offers a new built-in `useTransition()` Hook to help with this.
We can use it in three steps.
First, we'll make sure that we're actually using Concurrent Mode. We'll talk more about [adopting Concurrent Mode](/docs/concurrent-mode-adoption.html) later, but for now it's sufficient to know that we need to use `ReactDOM.createRoot()` rather than `ReactDOM.render()` for this feature to work:
```js
const rootElement = document.getElementById("root");
// Opt into Concurrent Mode
ReactDOM.createRoot(rootElement).render(<App />);
```
Next, we'll add an import for the `useTransition` Hook from React:
```js
import React, { useState, useTransition, Suspense } from "react";
```
Finally, we'll use it inside the `App` component:
```js{3-5}
function App() {
const [resource, setResource] = useState(initialResource);
const [startTransition, isPending] = useTransition({
timeoutMs: 3000
});
// ...
```
**By itself, this code doesn't do anything yet.** We will need to use this Hook's return values to set up our state transition. There are two values returned from `useTransition`:
* `startTransition` is a function. We'll use it to tell React *which* state update we want to defer.
* `isPending` is a boolean. It's React telling us whether that transition is ongoing at the moment.
We will use them right below.
Note we passed a configuration object to `useTransition`. Its `timeoutMs` property specifies **how long we're willing to wait for the transition to finish**. By passing `{timeoutMs: 3000}`, we say "If the next profile takes more than 3 seconds to load, show the big spinner -- but before that timeout it's okay to keep showing the previous screen".
### Wrapping setState in a Transition {#wrapping-setstate-in-a-transition}
Our "Next" button click handler sets the state that switches the current profile in the state:
```js{4}
<button
onClick={() => {
const nextUserId = getNextId(resource.userId);
setResource(fetchProfileData(nextUserId));
}}
>
```
We'll wrap that state update into `startTransition`. That's how we tell React **we don't mind React delaying that state update** if it leads to an undesirable loading state:
```js{3,6}
<button
onClick={() => {
startTransition(() => {
const nextUserId = getNextId(resource.userId);
setResource(fetchProfileData(nextUserId));
});
}}
>
```
**[Try it on CodeSandbox](https://codesandbox.io/s/vigilant-feynman-kpjy8w)**
Press "Next" a few times. Notice it already feels very different. **Instead of immediately seeing an empty screen on click, we now keep seeing the previous page for a while.** When the data has loaded, React transitions us to the new screen.
If we make our API responses take 5 seconds, [we can confirm](https://codesandbox.io/s/heuristic-leftpad-9hit59) that now React "gives up" and transitions anyway to the next screen after 3 seconds. This is because we passed `{timeoutMs: 3000}` to `useTransition()`. For example, if we passed `{timeoutMs: 60000}` instead, it would wait a whole minute.
### Adding a Pending Indicator {#adding-a-pending-indicator}
There's still something that feels broken about [our last example](https://codesandbox.io/s/vigilant-feynman-kpjy8w). Sure, it's nice not to see a "bad" loading state. **But having no indication of progress at all feels even worse!** When we click "Next", nothing happens and it feels like the app is broken.
Our `useTransition()` call returns two values: `startTransition` and `isPending`.
```js
const [startTransition, isPending] = useTransition({ timeoutMs: 3000 });
```
We've already used `startTransition` to wrap the state update. Now we're going to use `isPending` too. React gives this boolean to us so we can tell whether **we're currently waiting for this transition to finish**. We'll use it to indicate that something is happening:
```js{4,14}
return (
<>
<button
disabled={isPending}
onClick={() => {
startTransition(() => {
const nextUserId = getNextId(resource.userId);
setResource(fetchProfileData(nextUserId));
});
}}
>
Next
</button>
{isPending ? " Loading..." : null}
<ProfilePage resource={resource} />
</>
);
```
**[Try it on CodeSandbox](https://codesandbox.io/s/frosty-haslett-ds0h9h)**
Now, this feels a lot better! When we click Next, it gets disabled because clicking it multiple times doesn't make sense. And the new "Loading..." tells the user that the app didn't freeze.
### Reviewing the Changes {#reviewing-the-changes}
Let's take another look at all the changes we've made since the [original example](https://codesandbox.io/s/nice-shadow-zvosx0):
```js{3-5,9,11,14,19}
function App() {
const [resource, setResource] = useState(initialResource);
const [startTransition, isPending] = useTransition({
timeoutMs: 3000
});
return (
<>
<button
disabled={isPending}
onClick={() => {
startTransition(() => {
const nextUserId = getNextId(resource.userId);
setResource(fetchProfileData(nextUserId));
});
}}
>
Next
</button>
{isPending ? " Loading..." : null}
<ProfilePage resource={resource} />
</>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/frosty-haslett-ds0h9h)**
It took us only seven lines of code to add this transition:
* We've imported the `useTransition` Hook and used it in the component that updates the state.
* We've passed `{timeoutMs: 3000}` to stay on the previous screen for at most 3 seconds.
* We've wrapped our state update into `startTransition` to tell React it's okay to delay it.
* We're using `isPending` to communicate the state transition progress to the user and to disable the button.
As a result, clicking "Next" doesn't perform an immediate state transition to an "undesirable" loading state, but instead stays on the previous screen and communicates progress there.
### Where Does the Update Happen? {#where-does-the-update-happen}
This wasn't very difficult to implement. However, if you start thinking about how this could possibly work, it might become a little mindbending. If we set the state, how come we don't see the result right away? *Where* is the next `<ProfilePage>` rendering?
Clearly, both "versions" of `<ProfilePage>` exist at the same time. We know the old one exists because we see it on the screen and even display a progress indicator on it. And we know the new version also exists *somewhere*, because it's the one that we're waiting for!
**But how can two versions of the same component exist at the same time?**
This gets at the root of what Concurrent Mode is. We've [previously said](/docs/concurrent-mode-intro.html#intentional-loading-sequences) it's a bit like React working on state update on a "branch". Another way we can conceptualize is that wrapping a state update in `startTransition` begins rendering it *"in a different universe"*, much like in science fiction movies. We don't "see" that universe directly -- but we can get a signal from it that tells us something is happening (`isPending`). When the update is ready, our "universes" merge back together, and we see the result on the screen!
Play a bit more with the [demo](https://codesandbox.io/s/frosty-haslett-ds0h9h), and try to imagine it happening.
Of course, two versions of the tree rendering *at the same time* is an illusion, just like the idea that all programs run on your computer at the same time is an illusion. An operating system switches between different applications very fast. Similarly, React can switch between the version of the tree you see on the screen and the version that it's "preparing" to show next.
An API like `useTransition` lets you focus on the desired user experience, and not think about the mechanics of how it's implemented. Still, it can be a helpful metaphor to imagine that updates wrapped in `startTransition` happen "on a branch" or "in a different world".
### Transitions Are Everywhere {#transitions-are-everywhere}
As we learned from the [Suspense walkthrough](/docs/concurrent-mode-suspense.html), any component can "suspend" any time if some data it needs is not ready yet. We can strategically place `<Suspense>` boundaries in different parts of the tree to handle this, but it won't always be enough.
Let's get back to our [first Suspense demo](https://codesandbox.io/s/frosty-hermann-bztrp) where there was just one profile. Currently, it fetches the data only once. We'll add a "Refresh" button to check for server updates.
Our first attempt might look like this:
```js{6-8,13-15}
const initialResource = fetchUserAndPosts();
function ProfilePage() {
const [resource, setResource] = useState(initialResource);
function handleRefreshClick() {
setResource(fetchUserAndPosts());
}
return (
<Suspense fallback={<h1>Loading profile...</h1>}>
<ProfileDetails resource={resource} />
<button onClick={handleRefreshClick}>
Refresh
</button>
<Suspense fallback={<h1>Loading posts...</h1>}>
<ProfileTimeline resource={resource} />
</Suspense>
</Suspense>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/trusting-brown-6hj0m0)**
In this example, we start data fetching at the load *and* every time you press "Refresh". We put the result of calling `fetchUserAndPosts()` into state so that components below can start reading the new data from the request we just kicked off.
We can see in [this example](https://codesandbox.io/s/trusting-brown-6hj0m0) that pressing "Refresh" works. The `<ProfileDetails>` and `<ProfileTimeline>` components receive a new `resource` prop that represents the fresh data, they "suspend" because we don't have a response yet, and we see the fallbacks. When the response loads, we can see the updated posts (our fake API adds them every 3 seconds).
However, the experience feels really jarring. We were browsing a page, but it got replaced by a loading state right as we were interacting with it. It's disorienting. **Just like before, to avoid showing an undesirable loading state, we can wrap the state update in a transition:**
```js{2-5,9-11,21}
function ProfilePage() {
const [startTransition, isPending] = useTransition({
// Wait 10 seconds before fallback
timeoutMs: 10000
});
const [resource, setResource] = useState(initialResource);
function handleRefreshClick() {
startTransition(() => {
setResource(fetchProfileData());
});
}
return (
<Suspense fallback={<h1>Loading profile...</h1>}>
<ProfileDetails resource={resource} />
<button
onClick={handleRefreshClick}
disabled={isPending}
>
{isPending ? "Refreshing..." : "Refresh"}
</button>
<Suspense fallback={<h1>Loading posts...</h1>}>
<ProfileTimeline resource={resource} />
</Suspense>
</Suspense>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/zealous-mccarthy-fiiwu2)**
This feels a lot better! Clicking "Refresh" doesn't pull us away from the page we're browsing anymore. We see something is loading "inline", and when the data is ready, it's displayed.
### Baking Transitions Into the Design System {#baking-transitions-into-the-design-system}
We can now see that the need for `useTransition` is *very* common. Pretty much any button click or interaction that can lead to a component suspending needs to be wrapped in `useTransition` to avoid accidentally hiding something the user is interacting with.
This can lead to a lot of repetitive code across components. This is why **we generally recommend to bake `useTransition` into the *design system* components of your app**. For example, we can extract the transition logic into our own `<Button>` component:
```js{7-9,20,24}
function Button({ children, onClick }) {
const [startTransition, isPending] = useTransition({
timeoutMs: 10000
});
function handleClick() {
startTransition(() => {
onClick();
});
}
const spinner = (
// ...
);
return (
<>
<button
onClick={handleClick}
disabled={isPending}
>
{children}
</button>
{isPending ? spinner : null}
</>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/heuristic-cerf-8bo4rk)**
Note that the button doesn't care *what* state we're updating. It's wrapping *any* state updates that happen during its `onClick` handler into a transition. Now that our `<Button>` takes care of setting up the transition, the `<ProfilePage>` component doesn't need to set up its own:
```js{4-6,11-13}
function ProfilePage() {
const [resource, setResource] = useState(initialResource);
function handleRefreshClick() {
setResource(fetchProfileData());
}
return (
<Suspense fallback={<h1>Loading profile...</h1>}>
<ProfileDetails resource={resource} />
<Button onClick={handleRefreshClick}>
Refresh
</Button>
<Suspense fallback={<h1>Loading posts...</h1>}>
<ProfileTimeline resource={resource} />
</Suspense>
</Suspense>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/heuristic-cerf-8bo4rk)**
When a button gets clicked, it starts a transition and calls `props.onClick()` inside of it -- which triggers `handleRefreshClick` in the `<ProfilePage>` component. We start fetching the fresh data, but it doesn't trigger a fallback because we're inside a transition, and the 10 second timeout specified in the `useTransition` call hasn't passed yet. While a transition is pending, the button displays an inline loading indicator.
We can see now how Concurrent Mode helps us achieve a good user experience without sacrificing isolation and modularity of components. React coordinates the transition.
## The Three Steps {#the-three-steps}
By now we have discussed all of the different visual states that an update may go through. In this section, we will give them names and talk about the progression between them.
<br>
<img src="../images/docs/cm-steps-simple.png" alt="Three steps" />
At the very end, we have the **Complete** state. That's where we want to eventually get to. It represents the moment when the next screen is fully rendered and isn't loading more data.
But before our screen can be Complete, we might need to load some data or code. When we're on the next screen, but some parts of it are still loading, we call that a **Skeleton** state.
Finally, there are two primary ways that lead us to the Skeleton state. We will illustrate the difference between them with a concrete example.
### Default: Receded → Skeleton → Complete {#default-receded-skeleton-complete}
Open [this example](https://codesandbox.io/s/xenodochial-breeze-khk2fh) and click "Open Profile". You will see several visual states one by one:
* **Receded**: For a second, you will see the `<h1>Loading the app...</h1>` fallback.
* **Skeleton:** You will see the `<ProfilePage>` component with `<h2>Loading posts...</h2>` inside.
* **Complete:** You will see the `<ProfilePage>` component with no fallbacks inside. Everything was fetched.
How do we separate the Receded and the Skeleton states? The difference between them is that the **Receded** state feels like "taking a step back" to the user, while the **Skeleton** state feels like "taking a step forward" in our progress to show more content.
In this example, we started our journey on the `<HomePage>`:
```js
<Suspense fallback={...}>
{/* previous screen */}
<HomePage />
</Suspense>
```
After the click, React started rendering the next screen:
```js
<Suspense fallback={...}>
{/* next screen */}
<ProfilePage>
<ProfileDetails />
<Suspense fallback={...}>
<ProfileTimeline />
</Suspense>
</ProfilePage>
</Suspense>
```
Both `<ProfileDetails>` and `<ProfileTimeline>` need data to render, so they suspend:
```js{4,6}
<Suspense fallback={...}>
{/* next screen */}
<ProfilePage>
<ProfileDetails /> {/* suspends! */}
<Suspense fallback={<h2>Loading posts...</h2>}>
<ProfileTimeline /> {/* suspends! */}
</Suspense>
</ProfilePage>
</Suspense>
```
When a component suspends, React needs to show the closest fallback. But the closest fallback to `<ProfileDetails>` is at the top level:
```js{2,3,7}
<Suspense fallback={
// We see this fallback now because of <ProfileDetails>
<h1>Loading the app...</h1>
}>
{/* next screen */}
<ProfilePage>
<ProfileDetails /> {/* suspends! */}
<Suspense fallback={...}>
<ProfileTimeline />
</Suspense>
</ProfilePage>
</Suspense>
```
This is why when we click the button, it feels like we've "taken a step back". The `<Suspense>` boundary which was previously showing useful content (`<HomePage />`) had to "recede" to showing the fallback (`<h1>Loading the app...</h1>`). We call that a **Receded** state.
As we load more data, React will retry rendering, and `<ProfileDetails>` can render successfully. Finally, we're in the **Skeleton** state. We see the new page with missing parts:
```js{6,7,9}
<Suspense fallback={...}>
{/* next screen */}
<ProfilePage>
<ProfileDetails />
<Suspense fallback={
// We see this fallback now because of <ProfileTimeline>
<h2>Loading posts...</h2>
}>
<ProfileTimeline /> {/* suspends! */}
</Suspense>
</ProfilePage>
</Suspense>
```
Eventually, they load too, and we get to the **Complete** state.
This scenario (Receded → Skeleton → Complete) is the default one. However, the Receded state is not very pleasant because it "hides" existing information. This is why React lets us opt into a different sequence (**Pending** → Skeleton → Complete) with `useTransition`.
### Preferred: Pending → Skeleton → Complete {#preferred-pending-skeleton-complete}
When we `useTransition`, React will let us "stay" on the previous screen -- and show a progress indicator there. We call that a **Pending** state. It feels much better than the Receded state because none of our existing content disappears, and the page stays interactive.
You can compare these two examples to feel the difference:
* Default: [Receded → Skeleton → Complete](https://codesandbox.io/s/xenodochial-breeze-khk2fh)
* **Preferred: [Pending → Skeleton → Complete](https://codesandbox.io/s/serene-pascal-w3no1l)**
The only difference between these two examples is that the first uses regular `<button>`s, but the second one uses our custom `<Button>` component with `useTransition`.
### Wrap Lazy Features in `<Suspense>` {#wrap-lazy-features-in-suspense}
Open [this example](https://codesandbox.io/s/crazy-browser-0tdg6m). When you press a button, you'll see the Pending state for a second before moving on. This transition feels nice and fluid.
We will now add a brand new feature to the profile page -- a list of fun facts about a person:
```js{8,13-25}
function ProfilePage({ resource }) {
return (
<>
<ProfileDetails resource={resource} />
<Suspense fallback={<h2>Loading posts...</h2>}>
<ProfileTimeline resource={resource} />
</Suspense>
<ProfileTrivia resource={resource} />
</>
);
}
function ProfileTrivia({ resource }) {
const trivia = resource.trivia.read();
return (
<>
<h2>Fun Facts</h2>
<ul>
{trivia.map(fact => (
<li key={fact.id}>{fact.text}</li>
))}
</ul>
</>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/agitated-snowflake-m3scjk)**
If you press "Open Profile" now, you can tell something is wrong. It takes a whole seven seconds to make the transition now! This is because our trivia API is too slow. Let's say we can't make the API faster. How can we improve the user experience with this constraint?
If we don't want to stay in the Pending state for too long, our first instinct might be to set `timeoutMs` in `useTransition` to something smaller, like `3000`. You can try this [here](https://codesandbox.io/s/nervous-galileo-ln6pbh). This lets us escape the prolonged Pending state, but we still don't have anything useful to show!
There is a simpler way to solve this. **Instead of making the transition shorter, we can "disconnect" the slow component from the transition** by wrapping it into `<Suspense>`:
```js{8,10}
function ProfilePage({ resource }) {
return (
<>
<ProfileDetails resource={resource} />
<Suspense fallback={<h2>Loading posts...</h2>}>
<ProfileTimeline resource={resource} />
</Suspense>
<Suspense fallback={<h2>Loading fun facts...</h2>}>
<ProfileTrivia resource={resource} />
</Suspense>
</>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/mutable-silence-wffd1t)**
This reveals an important insight. React always prefers to go to the Skeleton state as soon as possible. Even if we use transitions with long timeouts everywhere, React will not stay in the Pending state for longer than necessary to avoid the Receded state.
**If some feature isn't a vital part of the next screen, wrap it in `<Suspense>` and let it load lazily.** This ensures we can show the rest of the content as soon as possible. Conversely, if a screen is *not worth showing* without some component, such as `<ProfileDetails>` in our example, do *not* wrap it in `<Suspense>`. Then the transitions will "wait" for it to be ready.
### Suspense Reveal "Train" {#suspense-reveal-train}
When we're already on the next screen, sometimes the data needed to "unlock" different `<Suspense>` boundaries arrives in quick succession. For example, two different responses might arrive after 1000ms and 1050ms, respectively. If you've already waited for a second, waiting another 50ms is not going to be perceptible. This is why React reveals `<Suspense>` boundaries on a schedule, like a "train" that arrives periodically. This trades a small delay for reducing the layout thrashing and the number of visual changes presented to the user.
You can see a demo of this [here](https://codesandbox.io/s/ecstatic-sammet-zeddc4). The "posts" and "fun facts" responses come within 100ms of each other. But React coalesces them and "reveals" their Suspense boundaries together.
### Delaying a Pending Indicator {#delaying-a-pending-indicator}
Our `Button` component will immediately show the Pending state indicator on click:
```js{2,13}
function Button({ children, onClick }) {
const [startTransition, isPending] = useTransition({
timeoutMs: 10000
});
// ...
return (
<>
<button onClick={handleClick} disabled={isPending}>
{children}
</button>
{isPending ? spinner : null}
</>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/jolly-http-n94od0)**
This signals to the user that some work is happening. However, if the transition is relatively short (less than 500ms), it might be too distracting and make the transition itself feel *slower*.
One possible solution to this is to *delay the spinner itself* from displaying:
```css
.DelayedSpinner {
animation: 0s linear 0.5s forwards makeVisible;
visibility: hidden;
}
@keyframes makeVisible {
to {
visibility: visible;
}
}
```
```js{2-4,10}
const spinner = (
<span className="DelayedSpinner">
{/* ... */}
</span>
);
return (
<>
<button onClick={handleClick}>{children}</button>
{isPending ? spinner : null}
</>
);
```
**[Try it on CodeSandbox](https://codesandbox.io/s/optimistic-night-4td1me)**
With this change, even though we're in the Pending state, we don't display any indication to the user until 500ms has passed. This may not seem like much of an improvement when the API responses are slow. But compare how it feels [before](https://codesandbox.io/s/priceless-water-yw7zw4) and [after](https://codesandbox.io/s/mystifying-noether-tnxftn) when the API call is fast. Even though the rest of the code hasn't changed, suppressing a "too fast" loading state improves the perceived performance by not calling attention to the delay.
### Recap {#recap}
The most important things we learned so far are:
* By default, our loading sequence is Receded → Skeleton → Complete.
* The Receded state doesn't feel very nice because it hides existing content.
* With `useTransition`, we can opt into showing a Pending state first instead. This will keep us on the previous screen while the next screen is being prepared.
* If we don't want some component to delay the transition, we can wrap it in its own `<Suspense>` boundary.
* Instead of doing `useTransition` in every other component, we can build it into our design system.
## Other Patterns {#other-patterns}
Transitions are probably the most common Concurrent Mode pattern you'll encounter, but there are a few more patterns you might find useful.
### Splitting High and Low Priority State {#splitting-high-and-low-priority-state}
When you design React components, it is usually best to find the "minimal representation" of state. For example, instead of keeping `firstName`, `lastName`, and `fullName` in state, it's usually better keep only `firstName` and `lastName`, and then calculate `fullName` during rendering. This lets us avoid mistakes where we update one state but forget the other state.
However, in Concurrent Mode there are cases where you might *want* to "duplicate" some data in different state variables. Consider this tiny translation app:
```js
const initialQuery = "Hello, world";
const initialResource = fetchTranslation(initialQuery);
function App() {
const [query, setQuery] = useState(initialQuery);
const [resource, setResource] = useState(initialResource);
function handleChange(e) {
const value = e.target.value;
setQuery(value);
setResource(fetchTranslation(value));
}
return (
<>
<input
value={query}
onChange={handleChange}
/>
<Suspense fallback={<p>Loading...</p>}>
<Translation resource={resource} />
</Suspense>
</>
);
}
function Translation({ resource }) {
return (
<p>
<b>{resource.read()}</b>
</p>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/boring-frost-t5ijqm)**
Notice how when you type into the input, the `<Translation>` component suspends, and we see the `<p>Loading...</p>` fallback until we get fresh results. This is not ideal. It would be better if we could see the *previous* translation for a bit while we're fetching the next one.
In fact, if we open the console, we'll see a warning:
```
Warning: App triggered a user-blocking update that suspended.
The fix is to split the update into multiple parts: a user-blocking update to provide immediate feedback, and another update that triggers the bulk of the changes.
Refer to the documentation for useTransition to learn how to implement this pattern.
```
As we mentioned earlier, if some state update causes a component to suspend, that state update should be wrapped in a transition. Let's add `useTransition` to our component:
```js{4-6,10,13}
function App() {
const [query, setQuery] = useState(initialQuery);
const [resource, setResource] = useState(initialResource);
const [startTransition, isPending] = useTransition({
timeoutMs: 5000
});
function handleChange(e) {
const value = e.target.value;
startTransition(() => {
setQuery(value);
setResource(fetchTranslation(value));
});
}
// ...
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/wizardly-swirles-476m52)**
Try typing into the input now. Something's wrong! The input is updating very slowly.
We've fixed the first problem (suspending outside of a transition). But now because of the transition, our state doesn't update immediately, and it can't "drive" a controlled input!
The answer to this problem **is to split the state in two parts:** a "high priority" part that updates immediately, and a "low priority" part that may wait for a transition.
In our example, we already have two state variables. The input text is in `query`, and we read the translation from `resource`. We want changes to the `query` state to happen immediately, but changes to the `resource` (i.e. fetching a new translation) should trigger a transition.
So the correct fix is to put `setQuery` (which doesn't suspend) *outside* the transition, but `setResource` (which will suspend) *inside* of it.
```js{4,5}
function handleChange(e) {
const value = e.target.value;
// Outside the transition (urgent)
setQuery(value);
startTransition(() => {
// Inside the transition (may be delayed)
setResource(fetchTranslation(value));
});
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/elegant-kalam-dhlrkz)**
With this change, it works as expected. We can type into the input immediately, and the translation later "catches up" to what we have typed.
### Deferring a Value {#deferring-a-value}
By default, React always renders a consistent UI. Consider code like this:
```js
<>
<ProfileDetails user={user} />
<ProfileTimeline user={user} />
</>
```
React guarantees that whenever we look at these components on the screen, they will reflect data from the same `user`. If a different `user` is passed down because of a state update, you would see them changing together. You can't ever record a screen and find a frame where they would show values from different `user`s. (If you ever run into a case like this, file a bug!)
This makes sense in the vast majority of situations. Inconsistent UI is confusing and can mislead users. (For example, it would be terrible if a messenger's Send button and the conversation picker pane "disagreed" about which thread is currently selected.)
However, sometimes it might be helpful to intentionally introduce an inconsistency. We could do it manually by "splitting" the state like above, but React also offers a built-in Hook for this:
```js
import { useDeferredValue } from 'react';
const deferredValue = useDeferredValue(value, {
timeoutMs: 5000
});
```
To demonstrate this feature, we'll use [the profile switcher example](https://codesandbox.io/s/quirky-carson-vs6g0i). Click the "Next" button and notice how it takes 1 second to do a transition.
Let's say that fetching the user details is very fast and only takes 300 milliseconds. Currently, we're waiting a whole second because we need both user details and posts to display a consistent profile page. But what if we want to show the details faster?
If we're willing to sacrifice consistency, we could **pass potentially stale data to the components that delay our transition**. That's what `useDeferredValue()` lets us do:
```js{2-4,10,11,21}
function ProfilePage({ resource }) {
const deferredResource = useDeferredValue(resource, {
timeoutMs: 1000
});
return (
<Suspense fallback={<h1>Loading profile...</h1>}>
<ProfileDetails resource={resource} />
<Suspense fallback={<h1>Loading posts...</h1>}>
<ProfileTimeline
resource={deferredResource}
isStale={deferredResource !== resource}
/>
</Suspense>
</Suspense>
);
}
function ProfileTimeline({ isStale, resource }) {
const posts = resource.posts.read();
return (
<ul style={{ opacity: isStale ? 0.7 : 1 }}>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/dazzling-fog-o6ovhr)**
The tradeoff we're making here is that `<ProfileTimeline>` will be inconsistent with other components and potentially show an older item. Click "Next" a few times, and you'll notice it. But thanks to that, we were able to cut down the transition time from 1000ms to 300ms.
Whether or not it's an appropriate tradeoff depends on the situation. But it's a handy tool, especially when the content doesn't change noticeably between items, and the user might not even realize they were looking at a stale version for a second.
It's worth noting that `useDeferredValue` is not *only* useful for data fetching. It also helps when an expensive component tree causes an interaction (e.g. typing in an input) to be sluggish. Just like we can "defer" a value that takes too long to fetch (and show its old value despite other components updating), we can do this with trees that take too long to render.
For example, consider a filterable list like this:
```js
function App() {
const [text, setText] = useState("hello");
function handleChange(e) {
setText(e.target.value);
}
return (
<div className="App">
<label>
Type into the input:{" "}
<input value={text} onChange={handleChange} />
</label>
...
<MySlowList text={text} />
</div>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/runtime-pine-kl2yff)**
In this example, **every item in `<MySlowList>` has an artificial slowdown -- each of them blocks the thread for a few milliseconds**. We'd never do this in a real app, but this helps us simulate what can happen in a deep component tree with no single obvious place to optimize.
We can see how typing in the input causes stutter. Now let's add `useDeferredValue`:
```js{3-5,18}
function App() {
const [text, setText] = useState("hello");
const deferredText = useDeferredValue(text, {
timeoutMs: 5000
});
function handleChange(e) {
setText(e.target.value);
}
return (
<div className="App">
<label>
Type into the input:{" "}
<input value={text} onChange={handleChange} />
</label>
...
<MySlowList text={deferredText} />
</div>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/charming-goldwasser-6kuh4m)**
Now typing has a lot less stutter -- although we pay for this by showing the results with a lag.
How is this different from debouncing? Our example has a fixed artificial delay (3ms for every one of 80 items), so there is always a delay, no matter how fast our computer is. However, the `useDeferredValue` value only "lags behind" if the rendering takes a while. There is no minimal lag imposed by React. With a more realistic workload, you can expect the lag to adjust to the user’s device. On fast machines, the lag would be smaller or non-existent, and on slow machines, it would be more noticeable. In both cases, the app would remain responsive. That’s the advantage of this mechanism over debouncing or throttling, which always impose a minimal delay and can't avoid blocking the thread while rendering.
Even though there is an improvement in responsiveness, this example isn't as compelling yet because Concurrent Mode is missing some crucial optimizations for this use case. Still, it is interesting to see that features like `useDeferredValue` (or `useTransition`) are useful regardless of whether we're waiting for network or for computational work to finish.
### SuspenseList {#suspenselist}
`<SuspenseList>` is the last pattern that's related to orchestrating loading states.
Consider this example:
```js{5-10}
function ProfilePage({ resource }) {
return (
<>
<ProfileDetails resource={resource} />
<Suspense fallback={<h2>Loading posts...</h2>}>
<ProfileTimeline resource={resource} />
</Suspense>
<Suspense fallback={<h2>Loading fun facts...</h2>}>
<ProfileTrivia resource={resource} />
</Suspense>
</>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/hardcore-river-14ecuq)**
The API call duration in this example is randomized. If you keep refreshing it, you will notice that sometimes the posts arrive first, and sometimes the "fun facts" arrive first.
This presents a problem. If the response for fun facts arrives first, we'll see the fun facts below the `<h2>Loading posts...</h2>` fallback for posts. We might start reading them, but then the *posts* response will come back, and shift all the facts down. This is jarring.
One way we could fix it is by putting them both in a single boundary:
```js
<Suspense fallback={<h2>Loading posts and fun facts...</h2>}>
<ProfileTimeline resource={resource} />
<ProfileTrivia resource={resource} />
</Suspense>
```
**[Try it on CodeSandbox](https://codesandbox.io/s/quirky-meadow-w1c61p)**
The problem with this is that now we *always* wait for both of them to be fetched. However, if it's the *posts* that came back first, there's no reason to delay showing them. When fun facts load later, they won't shift the layout because they're already below the posts.
Other approaches to this, such as composing Promises in a special way, are increasingly difficult to pull off when the loading states are located in different components down the tree.
To solve this, we will import `SuspenseList`:
```js
import { SuspenseList } from 'react';
```
`<SuspenseList>` coordinates the "reveal order" of the closest `<Suspense>` nodes below it:
```js{3,11}
function ProfilePage({ resource }) {
return (
<SuspenseList revealOrder="forwards">
<ProfileDetails resource={resource} />
<Suspense fallback={<h2>Loading posts...</h2>}>
<ProfileTimeline resource={resource} />
</Suspense>
<Suspense fallback={<h2>Loading fun facts...</h2>}>
<ProfileTrivia resource={resource} />
</Suspense>
</SuspenseList>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/empty-leaf-lp7eom)**
The `revealOrder="forwards"` option means that the closest `<Suspense>` nodes inside this list **will only "reveal" their content in the order they appear in the tree -- even if the data for them arrives in a different order**. `<SuspenseList>` has other interesting modes: try changing `"forwards"` to `"backwards"` or `"together"` and see what happens.
You can control how many loading states are visible at once with the `tail` prop. If we specify `tail="collapsed"`, we'll see *at most one* fallback at a time. You can play with it [here](https://codesandbox.io/s/keen-leaf-gccxd8).
Keep in mind that `<SuspenseList>` is composable, like anything in React. For example, you can create a grid by putting several `<SuspenseList>` rows inside a `<SuspenseList>` table.
## Next Steps {#next-steps}
Concurrent Mode offers a powerful UI programming model and a set of new composable primitives to help you orchestrate delightful user experiences.
It's a result of several years of research and development, but it's not finished. In the section on [adopting Concurrent Mode](/docs/concurrent-mode-adoption.html), we'll describe how you can try it and what you can expect.

204
content/docs/concurrent-mode-reference.md

@ -1,204 +0,0 @@
---
id: concurrent-mode-reference
title: Concurrent Mode API Reference (Experimental)
permalink: docs/concurrent-mode-reference.html
prev: concurrent-mode-adoption.html
---
<style>
.scary > blockquote {
background-color: rgba(237, 51, 21, 0.2);
border-left-color: #ed3315;
}
</style>
<div class="scary">
>Caution:
>
>This page was about experimental features that aren't yet available in a stable release. It was aimed at early adopters and people who are curious.
>
>Much of the information on this page is now outdated and exists only for archival purposes. **Please refer to the [React 18 Alpha announcement post](/blog/2021/06/08/the-plan-for-react-18.html
) for the up-to-date information.**
>
>Before React 18 is released, we will replace this page with stable documentation.
</div>
This page is an API reference for the React [Concurrent Mode](/docs/concurrent-mode-intro.html). If you're looking for a guided introduction instead, check out [Concurrent UI Patterns](/docs/concurrent-mode-patterns.html).
**Note: This is a Community Preview and not the final stable version. There will likely be future changes to these APIs. Use at your own risk!**
- [Enabling Concurrent Mode](#concurrent-mode)
- [`createRoot`](#createroot)
- [Suspense](#suspense)
- [`Suspense`](#suspensecomponent)
- [`SuspenseList`](#suspenselist)
- [`useTransition`](#usetransition)
- [`useDeferredValue`](#usedeferredvalue)
## Enabling Concurrent Mode {#concurrent-mode}
### `createRoot` {#createroot}
```js
ReactDOM.createRoot(rootNode).render(<App />);
```
Replaces `ReactDOM.render(<App />, rootNode)` and enables Concurrent Mode.
For more information on Concurrent Mode, check out the [Concurrent Mode documentation.](/docs/concurrent-mode-intro.html)
## Suspense API {#suspense}
### `Suspense` {#suspensecomponent}
```js
<Suspense fallback={<h1>Loading...</h1>}>
<ProfilePhoto />
<ProfileDetails />
</Suspense>
```
`Suspense` lets your components "wait" for something before they can render, showing a fallback while waiting.
In this example, `ProfileDetails` is waiting for an asynchronous API call to fetch some data. While we wait for `ProfileDetails` and `ProfilePhoto`, we will show the `Loading...` fallback instead. It is important to note that until all children inside `<Suspense>` have loaded, we will continue to show the fallback.
`Suspense` takes two props:
* **fallback** takes a loading indicator. The fallback is shown until all of the children of the `Suspense` component have finished rendering.
* **unstable_avoidThisFallback** takes a boolean. It tells React whether to "skip" revealing this boundary during the initial load. This API will likely be removed in a future release.
### `<SuspenseList>` {#suspenselist}
```js
<SuspenseList revealOrder="forwards">
<Suspense fallback={'Loading...'}>
<ProfilePicture id={1} />
</Suspense>
<Suspense fallback={'Loading...'}>
<ProfilePicture id={2} />
</Suspense>
<Suspense fallback={'Loading...'}>
<ProfilePicture id={3} />
</Suspense>
...
</SuspenseList>
```
`SuspenseList` helps coordinate many components that can suspend by orchestrating the order in which these components are revealed to the user.
When multiple components need to fetch data, this data may arrive in an unpredictable order. However, if you wrap these items in a `SuspenseList`, React will not show an item in the list until previous items have been displayed (this behavior is adjustable).
`SuspenseList` takes two props:
* **revealOrder (forwards, backwards, together)** defines the order in which the `SuspenseList` children should be revealed.
* `together` reveals *all* of them when they're ready instead of one by one.
* **tail (collapsed, hidden)** dictates how unloaded items in a `SuspenseList` is shown.
* By default, `SuspenseList` will show all fallbacks in the list.
* `collapsed` shows only the next fallback in the list.
* `hidden` doesn't show any unloaded items.
Note that `SuspenseList` only operates on the closest `Suspense` and `SuspenseList` components below it. It does not search for boundaries deeper than one level. However, it is possible to nest multiple `SuspenseList` components in each other to build grids.
### `useTransition` {#usetransition}
```js
const SUSPENSE_CONFIG = { timeoutMs: 2000 };
const [startTransition, isPending] = useTransition(SUSPENSE_CONFIG);
```
`useTransition` allows components to avoid undesirable loading states by waiting for content to load before **transitioning to the next screen**. It also allows components to defer slower, data fetching updates until subsequent renders so that more crucial updates can be rendered immediately.
The `useTransition` hook returns two values in an array.
* `startTransition` is a function that takes a callback. We can use it to tell React which state we want to defer.
* `isPending` is a boolean. It's React's way of informing us whether we're waiting for the transition to finish.
**If some state update causes a component to suspend, that state update should be wrapped in a transition.**
```js
const SUSPENSE_CONFIG = { timeoutMs: 2000 };
function App() {
const [resource, setResource] = useState(initialResource);
const [startTransition, isPending] = useTransition(SUSPENSE_CONFIG);
return (
<>
<button
disabled={isPending}
onClick={() => {
startTransition(() => {
const nextUserId = getNextId(resource.userId);
setResource(fetchProfileData(nextUserId));
});
}}
>
Next
</button>
{isPending ? " Loading..." : null}
<Suspense fallback={<Spinner />}>
<ProfilePage resource={resource} />
</Suspense>
</>
);
}
```
In this code, we've wrapped our data fetching with `startTransition`. This allows us to start fetching the profile data right away, while deferring the render of the next profile page and its associated `Spinner` for 2 seconds (the time shown in `timeoutMs`).
The `isPending` boolean lets React know that our component is transitioning, so we are able to let the user know this by showing some loading text on the previous profile page.
**For an in-depth look at transitions, you can read [Concurrent UI Patterns](/docs/concurrent-mode-patterns.html#transitions).**
#### useTransition Config {#usetransition-config}
```js
const SUSPENSE_CONFIG = { timeoutMs: 2000 };
```
`useTransition` accepts an **optional Suspense Config** with a `timeoutMs`. This timeout (in milliseconds) tells React how long to wait before showing the next state (the new Profile Page in the above example).
**Note: We recommend that you share Suspense Config between different modules.**
### `useDeferredValue` {#usedeferredvalue}
```js
const deferredValue = useDeferredValue(value, { timeoutMs: 2000 });
```
Returns a deferred version of the value that may "lag behind" it for at most `timeoutMs`.
This is commonly used to keep the interface responsive when you have something that renders immediately based on user input and something that needs to wait for a data fetch.
A good example of this is a text input.
```js
function App() {
const [text, setText] = useState("hello");
const deferredText = useDeferredValue(text, { timeoutMs: 2000 });
return (
<div className="App">
{/* Keep passing the current text to the input */}
<input value={text} onChange={handleChange} />
...
{/* But the list is allowed to "lag behind" when necessary */}
<MySlowList text={deferredText} />
</div>
);
}
```
This allows us to start showing the new text for the `input` immediately, which allows the webpage to feel responsive. Meanwhile, `MySlowList` "lags behind" for up to 2 seconds according to the `timeoutMs` before updating, allowing it to render with the current text in the background.
**For an in-depth look at deferring values, you can read [Concurrent UI Patterns](/docs/concurrent-mode-patterns.html#deferring-a-value).**
#### useDeferredValue Config {#usedeferredvalue-config}
```js
const SUSPENSE_CONFIG = { timeoutMs: 2000 };
```
`useDeferredValue` accepts an **optional Suspense Config** with a `timeoutMs`. This timeout (in milliseconds) tells React how long the deferred value is allowed to lag behind.
React will always try to use a shorter lag when network and device allows it.

739
content/docs/concurrent-mode-suspense.md

@ -1,739 +0,0 @@
---
id: concurrent-mode-suspense
title: Suspense for Data Fetching (Experimental)
permalink: docs/concurrent-mode-suspense.html
prev: concurrent-mode-intro.html
next: concurrent-mode-patterns.html
---
<style>
.scary > blockquote {
background-color: rgba(237, 51, 21, 0.2);
border-left-color: #ed3315;
}
</style>
<div class="scary">
>Caution:
>
>This page was about experimental features that aren't yet available in a stable release. It was aimed at early adopters and people who are curious.
>
>Much of the information on this page is now outdated and exists only for archival purposes. **Please refer to the [React 18 Alpha announcement post](/blog/2021/06/08/the-plan-for-react-18.html
) for the up-to-date information.**
>
>Before React 18 is released, we will replace this page with stable documentation.
</div>
React 16.6 added a `<Suspense>` component that lets you "wait" for some code to load and declaratively specify a loading state (like a spinner) while we're waiting:
```jsx
const ProfilePage = React.lazy(() => import('./ProfilePage')); // Lazy-loaded
// Show a spinner while the profile is loading
<Suspense fallback={<Spinner />}>
<ProfilePage />
</Suspense>
```
Suspense for Data Fetching is a new feature that lets you also use `<Suspense>` to **declaratively "wait" for anything else, including data.** This page focuses on the data fetching use case, but it can also wait for images, scripts, or other asynchronous work.
- [What Is Suspense, Exactly?](#what-is-suspense-exactly)
- [What Suspense Is Not](#what-suspense-is-not)
- [What Suspense Lets You Do](#what-suspense-lets-you-do)
- [Using Suspense in Practice](#using-suspense-in-practice)
- [What If I Don’t Use Relay?](#what-if-i-dont-use-relay)
- [For Library Authors](#for-library-authors)
- [Traditional Approaches vs Suspense](#traditional-approaches-vs-suspense)
- [Approach 1: Fetch-on-Render (not using Suspense)](#approach-1-fetch-on-render-not-using-suspense)
- [Approach 2: Fetch-Then-Render (not using Suspense)](#approach-2-fetch-then-render-not-using-suspense)
- [Approach 3: Render-as-You-Fetch (using Suspense)](#approach-3-render-as-you-fetch-using-suspense)
- [Start Fetching Early](#start-fetching-early)
- [We’re Still Figuring This Out](#were-still-figuring-this-out)
- [Suspense and Race Conditions](#suspense-and-race-conditions)
- [Race Conditions with useEffect](#race-conditions-with-useeffect)
- [Race Conditions with componentDidUpdate](#race-conditions-with-componentdidupdate)
- [The Problem](#the-problem)
- [Solving Race Conditions with Suspense](#solving-race-conditions-with-suspense)
- [Handling Errors](#handling-errors)
- [Next Steps](#next-steps)
## What Is Suspense, Exactly? {#what-is-suspense-exactly}
Suspense lets your components "wait" for something before they can render. In [this example](https://codesandbox.io/s/frosty-hermann-bztrp), two components wait for an asynchronous API call to fetch some data:
```js
const resource = fetchProfileData();
function ProfilePage() {
return (
<Suspense fallback={<h1>Loading profile...</h1>}>
<ProfileDetails />
<Suspense fallback={<h1>Loading posts...</h1>}>
<ProfileTimeline />
</Suspense>
</Suspense>
);
}
function ProfileDetails() {
// Try to read user info, although it might not have loaded yet
const user = resource.user.read();
return <h1>{user.name}</h1>;
}
function ProfileTimeline() {
// Try to read posts, although they might not have loaded yet
const posts = resource.posts.read();
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/frosty-hermann-bztrp)**
This demo is a teaser. Don't worry if it doesn't quite make sense yet. We'll talk more about how it works below. Keep in mind that Suspense is more of a *mechanism*, and particular APIs like `fetchProfileData()` or `resource.posts.read()` in the above example are not very important. If you're curious, you can find their definitions right in the [demo sandbox](https://codesandbox.io/s/frosty-hermann-bztrp).
Suspense is not a data fetching library. It's a **mechanism for data fetching libraries** to communicate to React that *the data a component is reading is not ready yet*. React can then wait for it to be ready and update the UI. At Facebook, we use Relay and its [new Suspense integration](https://relay.dev/docs/getting-started/step-by-step-guide/). We expect that other libraries like Apollo can provide similar integrations.
In the long term, we intend Suspense to become the primary way to read asynchronous data from components -- no matter where that data is coming from.
### What Suspense Is Not {#what-suspense-is-not}
Suspense is significantly different from existing approaches to these problems, so reading about it for the first time often leads to misconceptions. Let's clarify the most common ones:
* **It is not a data fetching implementation.** It does not assume that you use GraphQL, REST, or any other particular data format, library, transport, or protocol.
* **It is not a ready-to-use client.** You can't "replace" `fetch` or Relay with Suspense. But you can use a library that's integrated with Suspense (for example, [new Relay APIs](https://relay.dev/docs/api-reference/relay-environment-provider/)).
* **It does not couple data fetching to the view layer.** It helps orchestrate displaying the loading states in your UI, but it doesn't tie your network logic to React components.
### What Suspense Lets You Do {#what-suspense-lets-you-do}
So what's the point of Suspense? There are a few ways we can answer this:
* **It lets data fetching libraries deeply integrate with React.** If a data fetching library implements Suspense support, using it from React components feels very natural.
* **It lets you orchestrate intentionally designed loading states.** It doesn't say _how_ the data is fetched, but it lets you closely control the visual loading sequence of your app.
* **It helps you avoid race conditions.** Even with `await`, asynchronous code is often error-prone. Suspense feels more like reading data *synchronously* — as if it were already loaded.
## Using Suspense in Practice {#using-suspense-in-practice}
At Facebook, so far we have only used the Relay integration with Suspense in production. **If you're looking for a practical guide to get started today, [check out the Relay Guide](https://relay.dev/docs/getting-started/step-by-step-guide/)!** It demonstrates patterns that have already worked well for us in production.
**The code demos on this page use a "fake" API implementation rather than Relay.** This makes them easier to understand if you're not familiar with GraphQL, but they won't tell you the "right way" to build an app with Suspense. This page is more conceptual and is intended to help you see *why* Suspense works in a certain way, and which problems it solves.
### What If I Don't Use Relay? {#what-if-i-dont-use-relay}
If you don't use Relay today, you might have to wait before you can really try Suspense in your app. So far, it's the only implementation that we tested in production and are confident in.
Over the next several months, many libraries will appear with different takes on Suspense APIs. **If you prefer to learn when things are more stable, you might prefer to ignore this work for now, and come back when the Suspense ecosystem is more mature.**
You can also write your own integration for a data fetching library, if you'd like.
### For Library Authors {#for-library-authors}
We expect to see a lot of experimentation in the community with other libraries. There is one important thing to note for data fetching library authors.
Although it's technically doable, Suspense is **not** currently intended as a way to start fetching data when a component renders. Rather, it lets components express that they're "waiting" for data that is *already being fetched*. **[Building Great User Experiences with Concurrent Mode and Suspense](/blog/2019/11/06/building-great-user-experiences-with-concurrent-mode-and-suspense.html) describes why this matters and how to implement this pattern in practice.**
Unless you have a solution that helps prevent waterfalls, we suggest to prefer APIs that favor or enforce fetching before render. For a concrete example, you can look at how [Relay Suspense API](https://relay.dev/docs/api-reference/use-preloaded-query/) enforces preloading. Our messaging about this hasn't been very consistent in the past. Suspense for Data Fetching is still experimental, so you can expect our recommendations to change over time as we learn more from production usage and understand the problem space better.
## Traditional Approaches vs Suspense {#traditional-approaches-vs-suspense}
We could introduce Suspense without mentioning the popular data fetching approaches. However, this makes it more difficult to see which problems Suspense solves, why these problems are worth solving, and how Suspense is different from the existing solutions.
Instead, we'll look at Suspense as a logical next step in a sequence of approaches:
* **Fetch-on-render (for example, `fetch` in `useEffect`):** Start rendering components. Each of these components may trigger data fetching in their effects and lifecycle methods. This approach often leads to "waterfalls".
* **Fetch-then-render (for example, Relay without Suspense):** Start fetching all the data for the next screen as early as possible. When the data is ready, render the new screen. We can't do anything until the data arrives.
* **Render-as-you-fetch (for example, Relay with Suspense):** Start fetching all the required data for the next screen as early as possible, and start rendering the new screen *immediately — before we get a network response*. As data streams in, React retries rendering components that still need data until they're all ready.
>Note
>
>This is a bit simplified, and in practice solutions tend to use a mix of different approaches. Still, we will look at them in isolation to better contrast their tradeoffs.
To compare these approaches, we'll implement a profile page with each of them.
### Approach 1: Fetch-on-Render (not using Suspense) {#approach-1-fetch-on-render-not-using-suspense}
A common way to fetch data in React apps today is to use an effect:
```js
// In a function component:
useEffect(() => {
fetchSomething();
}, []);
// Or, in a class component:
componentDidMount() {
fetchSomething();
}
```
We call this approach "fetch-on-render" because it doesn't start fetching until *after* the component has rendered on the screen. This leads to a problem known as a "waterfall".
Consider these `<ProfilePage>` and `<ProfileTimeline>` components:
```js{4-6,22-24}
function ProfilePage() {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser().then(u => setUser(u));
}, []);
if (user === null) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline />
</>
);
}
function ProfileTimeline() {
const [posts, setPosts] = useState(null);
useEffect(() => {
fetchPosts().then(p => setPosts(p));
}, []);
if (posts === null) {
return <h2>Loading posts...</h2>;
}
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/fast-glade-rqnhtt)**
If you run this code and watch the console logs, you'll notice the sequence is:
1. We start fetching user details
2. We wait...
3. We finish fetching user details
4. We start fetching posts
5. We wait...
6. We finish fetching posts
If fetching user details takes three seconds, we'll only *start* fetching the posts after three seconds! That's a "waterfall": an unintentional *sequence* that should have been parallelized.
Waterfalls are common in code that fetches data on render. They're possible to solve, but as the product grows, many people prefer to use a solution that guards against this problem.
### Approach 2: Fetch-Then-Render (not using Suspense) {#approach-2-fetch-then-render-not-using-suspense}
Libraries can prevent waterfalls by offering a more centralized way to do data fetching. For example, Relay solves this problem by moving the information about the data a component needs to statically analyzable *fragments*, which later get composed into a single query.
On this page, we don't assume knowledge of Relay, so we won't be using it for this example. Instead, we'll write something similar manually by combining our data fetching methods:
```js
function fetchProfileData() {
return Promise.all([
fetchUser(),
fetchPosts()
]).then(([user, posts]) => {
return {user, posts};
})
}
```
In this example, `<ProfilePage>` waits for both requests but starts them in parallel:
```js{1,2,8-13}
// Kick off fetching as early as possible
const promise = fetchProfileData();
function ProfilePage() {
const [user, setUser] = useState(null);
const [posts, setPosts] = useState(null);
useEffect(() => {
promise.then(data => {
setUser(data.user);
setPosts(data.posts);
});
}, []);
if (user === null) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline posts={posts} />
</>
);
}
// The child doesn't trigger fetching anymore
function ProfileTimeline({ posts }) {
if (posts === null) {
return <h2>Loading posts...</h2>;
}
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/hopeful-lake-loddz9)**
The event sequence now becomes like this:
1. We start fetching user details
2. We start fetching posts
3. We wait...
4. We finish fetching user details
5. We finish fetching posts
We've solved the previous network "waterfall", but accidentally introduced a different one. We wait for *all* data to come back with `Promise.all()` inside `fetchProfileData`, so now we can't render profile details until the posts have been fetched too. We have to wait for both.
Of course, this is possible to fix in this particular example. We could remove the `Promise.all()` call, and wait for both Promises separately. However, this approach gets progressively more difficult as the complexity of our data and component tree grows. It's hard to write reliable components when arbitrary parts of the data tree may be missing or stale. So fetching all data for the new screen and *then* rendering is often a more practical option.
### Approach 3: Render-as-You-Fetch (using Suspense) {#approach-3-render-as-you-fetch-using-suspense}
In the previous approach, we fetched data before we called `setState`:
1. Start fetching
2. Finish fetching
3. Start rendering
With Suspense, we still start fetching first, but we flip the last two steps around:
1. Start fetching
2. **Start rendering**
3. **Finish fetching**
**With Suspense, we don't wait for the response to come back before we start rendering.** In fact, we start rendering *pretty much immediately* after kicking off the network request:
```js{2,17,23}
// This is not a Promise. It's a special object from our Suspense integration.
const resource = fetchProfileData();
function ProfilePage() {
return (
<Suspense fallback={<h1>Loading profile...</h1>}>
<ProfileDetails />
<Suspense fallback={<h1>Loading posts...</h1>}>
<ProfileTimeline />
</Suspense>
</Suspense>
);
}
function ProfileDetails() {
// Try to read user info, although it might not have loaded yet
const user = resource.user.read();
return <h1>{user.name}</h1>;
}
function ProfileTimeline() {
// Try to read posts, although they might not have loaded yet
const posts = resource.posts.read();
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/frosty-hermann-bztrp)**
Here's what happens when we render `<ProfilePage>` on the screen:
1. We've already kicked off the requests in `fetchProfileData()`. It gave us a special "resource" instead of a Promise. In a realistic example, it would be provided by our data library's Suspense integration, like Relay.
2. React tries to render `<ProfilePage>`. It returns `<ProfileDetails>` and `<ProfileTimeline>` as children.
3. React tries to render `<ProfileDetails>`. It calls `resource.user.read()`. None of the data is fetched yet, so this component "suspends". React skips over it, and tries rendering other components in the tree.
4. React tries to render `<ProfileTimeline>`. It calls `resource.posts.read()`. Again, there's no data yet, so this component also "suspends". React skips over it too, and tries rendering other components in the tree.
5. There's nothing left to try rendering. Because `<ProfileDetails>` suspended, React shows the closest `<Suspense>` fallback above it in the tree: `<h1>Loading profile...</h1>`. We're done for now.
This `resource` object represents the data that isn't there yet, but might eventually get loaded. When we call `read()`, we either get the data, or the component "suspends".
**As more data streams in, React will retry rendering, and each time it might be able to progress "deeper".** When `resource.user` is fetched, the `<ProfileDetails>` component will render successfully and we'll no longer need the `<h1>Loading profile...</h1>` fallback. Eventually, we'll get all the data, and there will be no fallbacks on the screen.
This has an interesting implication. Even if we use a GraphQL client that collects all data requirements in a single request, *streaming the response lets us show more content sooner*. Because we render-*as-we-fetch* (as opposed to *after* fetching), if `user` appears in the response earlier than `posts`, we'll be able to "unlock" the outer `<Suspense>` boundary before the response even finishes. We might have missed this earlier, but even the fetch-then-render solution contained a waterfall: between fetching and rendering. Suspense doesn't inherently suffer from this waterfall, and libraries like Relay take advantage of this.
Note how we eliminated the `if (...)` "is loading" checks from our components. This doesn't only remove boilerplate code, but it also simplifies making quick design changes. For example, if we wanted profile details and posts to always "pop in" together, we could delete the `<Suspense>` boundary between them. Or we could make them independent from each other by giving each *its own* `<Suspense>` boundary. Suspense lets us change the granularity of our loading states and orchestrate their sequencing without invasive changes to our code.
## Start Fetching Early {#start-fetching-early}
If you're working on a data fetching library, there's a crucial aspect of Render-as-You-Fetch you don't want to miss. **We kick off fetching _before_ rendering.** Look at this code example closer:
```js
// Start fetching early!
const resource = fetchProfileData();
// ...
function ProfileDetails() {
// Try to read user info
const user = resource.user.read();
return <h1>{user.name}</h1>;
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/frosty-hermann-bztrp)**
Note that the `read()` call in this example doesn't *start* fetching. It only tries to read the data that is **already being fetched**. This difference is crucial to creating fast applications with Suspense. We don't want to delay loading data until a component starts rendering. As a data fetching library author, you can enforce this by making it impossible to get a `resource` object without also starting a fetch. Every demo on this page using our "fake API" enforces this.
You might object that fetching "at the top level" like in this example is impractical. What are we going to do if we navigate to another profile's page? We might want to fetch based on props. The answer to this is **we want to start fetching in the event handlers instead**. Here is a simplified example of navigating between user's pages:
```js{1,2,10,11}
// First fetch: as soon as possible
const initialResource = fetchProfileData(0);
function App() {
const [resource, setResource] = useState(initialResource);
return (
<>
<button onClick={() => {
const nextUserId = getNextId(resource.userId);
// Next fetch: when the user clicks
setResource(fetchProfileData(nextUserId));
}}>
Next
</button>
<ProfilePage resource={resource} />
</>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/sparkling-field-41z4r3)**
With this approach, we can **fetch code and data in parallel**. When we navigate between pages, we don't need to wait for a page's code to load to start loading its data. We can start fetching both code and data at the same time (during the link click), delivering a much better user experience.
This poses a question of how do we know *what* to fetch before rendering the next screen. There are several ways to solve this (for example, by integrating data fetching closer with your routing solution). If you work on a data fetching library, [Building Great User Experiences with Concurrent Mode and Suspense](/blog/2019/11/06/building-great-user-experiences-with-concurrent-mode-and-suspense.html) presents a deep dive on how to accomplish this and why it's important.
### We're Still Figuring This Out {#were-still-figuring-this-out}
Suspense itself as a mechanism is flexible and doesn't have many constraints. Product code needs to be more constrained to ensure no waterfalls, but there are different ways to provide these guarantees. Some questions that we're currently exploring include:
* Fetching early can be cumbersome to express. How do we make it easier to avoid waterfalls?
* When we fetch data for a page, can the API encourage including data for instant transitions *from* it?
* What is the lifetime of a response? Should caching be global or local? Who manages the cache?
* Can Proxies help express lazy-loaded APIs without inserting `read()` calls everywhere?
* What would the equivalent of composing GraphQL queries look like for arbitrary Suspense data?
Relay has its own answers to some of these questions. There is certainly more than a single way to do it, and we're excited to see what new ideas the React community comes up with.
## Suspense and Race Conditions {#suspense-and-race-conditions}
Race conditions are bugs that happen due to incorrect assumptions about the order in which our code may run. Fetching data in the `useEffect` Hook or in class lifecycle methods like `componentDidUpdate` often leads to them. Suspense can help here, too — let's see how.
To demonstrate the issue, we will add a top-level `<App>` component that renders our `<ProfilePage>` with a button that lets us **switch between different profiles**:
```js{9-11}
function getNextId(id) {
// ...
}
function App() {
const [id, setId] = useState(0);
return (
<>
<button onClick={() => setId(getNextId(id))}>
Next
</button>
<ProfilePage id={id} />
</>
);
}
```
Let's compare how different data fetching strategies deal with this requirement.
### Race Conditions with `useEffect` {#race-conditions-with-useeffect}
First, we'll try a version of our original "fetch in effect" example. We'll modify it to pass an `id` parameter from the `<ProfilePage>` props to `fetchUser(id)` and `fetchPosts(id)`:
```js{1,5,6,14,19,23,24}
function ProfilePage({ id }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(id).then(u => setUser(u));
}, [id]);
if (user === null) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline id={id} />
</>
);
}
function ProfileTimeline({ id }) {
const [posts, setPosts] = useState(null);
useEffect(() => {
fetchPosts(id).then(p => setPosts(p));
}, [id]);
if (posts === null) {
return <h2>Loading posts...</h2>;
}
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/beautiful-mendeleev-qwyxzg)**
Note how we also changed the effect dependencies from `[]` to `[id]` — because we want the effect to re-run when the `id` changes. Otherwise, we wouldn't refetch new data.
If we try this code, it might seem like it works at first. However, if we randomize the delay time in our "fake API" implementation and press the "Next" button fast enough, we'll see from the console logs that something is going very wrong. **Requests from the previous profiles may sometimes "come back" after we've already switched the profile to another ID -- and in that case they can overwrite the new state with a stale response for a different ID.**
This problem is possible to fix (you could use the effect cleanup function to either ignore or cancel stale requests), but it's unintuitive and difficult to debug.
### Race Conditions with `componentDidUpdate` {#race-conditions-with-componentdidupdate}
One might think that this is a problem specific to `useEffect` or Hooks. Maybe if we port this code to classes or use convenient syntax like `async` / `await`, it will solve the problem?
Let's try that:
```js
class ProfilePage extends React.Component {
state = {
user: null,
};
componentDidMount() {
this.fetchData(this.props.id);
}
componentDidUpdate(prevProps) {
if (prevProps.id !== this.props.id) {
this.fetchData(this.props.id);
}
}
async fetchData(id) {
const user = await fetchUser(id);
this.setState({ user });
}
render() {
const { id } = this.props;
const { user } = this.state;
if (user === null) {
return <p>Loading profile...</p>;
}
return (
<>
<h1>{user.name}</h1>
<ProfileTimeline id={id} />
</>
);
}
}
class ProfileTimeline extends React.Component {
state = {
posts: null,
};
componentDidMount() {
this.fetchData(this.props.id);
}
componentDidUpdate(prevProps) {
if (prevProps.id !== this.props.id) {
this.fetchData(this.props.id);
}
}
async fetchData(id) {
const posts = await fetchPosts(id);
this.setState({ posts });
}
render() {
const { posts } = this.state;
if (posts === null) {
return <h2>Loading posts...</h2>;
}
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/async-wind-9o4ojn)**
This code is deceptively easy to read.
Unfortunately, neither using a class nor the `async` / `await` syntax helped us solve this problem. This version suffers from exactly the same race conditions, for the same reasons.
### The Problem {#the-problem}
React components have their own "lifecycle". They may receive props or update state at any point in time. However, each asynchronous request *also* has its own "lifecycle". It starts when we kick it off, and finishes when we get a response. The difficulty we're experiencing is "synchronizing" several processes in time that affect each other. This is hard to think about.
### Solving Race Conditions with Suspense {#solving-race-conditions-with-suspense}
Let's rewrite this example again, but using Suspense only:
```js
const initialResource = fetchProfileData(0);
function App() {
const [resource, setResource] = useState(initialResource);
return (
<>
<button onClick={() => {
const nextUserId = getNextId(resource.userId);
setResource(fetchProfileData(nextUserId));
}}>
Next
</button>
<ProfilePage resource={resource} />
</>
);
}
function ProfilePage({ resource }) {
return (
<Suspense fallback={<h1>Loading profile...</h1>}>
<ProfileDetails resource={resource} />
<Suspense fallback={<h1>Loading posts...</h1>}>
<ProfileTimeline resource={resource} />
</Suspense>
</Suspense>
);
}
function ProfileDetails({ resource }) {
const user = resource.user.read();
return <h1>{user.name}</h1>;
}
function ProfileTimeline({ resource }) {
const posts = resource.posts.read();
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.text}</li>
))}
</ul>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/sparkling-field-41z4r3)**
In the previous Suspense example, we only had one `resource`, so we held it in a top-level variable. Now that we have multiple resources, we moved it to the `<App>`'s component state:
```js{4}
const initialResource = fetchProfileData(0);
function App() {
const [resource, setResource] = useState(initialResource);
```
When we click "Next", the `<App>` component kicks off a request for the next profile, and passes *that* object down to the `<ProfilePage>` component:
```js{4,8}
<>
<button onClick={() => {
const nextUserId = getNextId(resource.userId);
setResource(fetchProfileData(nextUserId));
}}>
Next
</button>
<ProfilePage resource={resource} />
</>
```
Again, notice that **we're not waiting for the response to set the state. It's the other way around: we set the state (and start rendering) immediately after kicking off a request**. As soon as we have more data, React "fills in" the content inside `<Suspense>` components.
This code is very readable, but unlike the examples earlier, the Suspense version doesn't suffer from race conditions. You might be wondering why. The answer is that in the Suspense version, we don't have to think about *time* as much in our code. Our original code with race conditions needed to set the state *at the right moment later*, or otherwise it would be wrong. But with Suspense, we set the state *immediately* -- so it's harder to mess it up.
## Handling Errors {#handling-errors}
When we write code with Promises, we might use `catch()` to handle errors. How does this work with Suspense, given that we don't *wait* for Promises to start rendering?
With Suspense, handling fetching errors works the same way as handling rendering errors -- you can render an [error boundary](/docs/error-boundaries.html) anywhere to "catch" errors in components below.
First, we'll define an error boundary component to use across our project:
```js
// Error boundaries currently have to be classes.
class ErrorBoundary extends React.Component {
state = { hasError: false, error: null };
static getDerivedStateFromError(error) {
return {
hasError: true,
error
};
}
render() {
if (this.state.hasError) {
return this.props.fallback;
}
return this.props.children;
}
}
```
And then we can put it anywhere in the tree to catch errors:
```js{5,9}
function ProfilePage() {
return (
<Suspense fallback={<h1>Loading profile...</h1>}>
<ProfileDetails />
<ErrorBoundary fallback={<h2>Could not fetch posts.</h2>}>
<Suspense fallback={<h1>Loading posts...</h1>}>
<ProfileTimeline />
</Suspense>
</ErrorBoundary>
</Suspense>
);
}
```
**[Try it on CodeSandbox](https://codesandbox.io/s/sparkling-rgb-r5vfhs)**
It would catch both rendering errors *and* errors from Suspense data fetching. We can have as many error boundaries as we like but it's best to [be intentional](https://aweary.dev/fault-tolerance-react/) about their placement.
## Next Steps {#next-steps}
We've now covered the basics of Suspense for Data Fetching! Importantly, we now better understand *why* Suspense works this way, and how it fits into the data fetching space.
Suspense answers some questions, but it also poses new questions of its own:
* If some component "suspends", does the app freeze? How to avoid this?
* What if we want to show a spinner in a different place than "above" the component in a tree?
* If we intentionally *want* to show an inconsistent UI for a small period of time, can we do that?
* Instead of showing a spinner, can we add a visual effect like "greying out" the current screen?
* Why does our [last Suspense example](https://codesandbox.io/s/sparkling-field-41z4r3) log a warning when clicking the "Next" button?
To answer these questions, we will refer to the next section on [Concurrent UI Patterns](/docs/concurrent-mode-patterns.html).

4
content/docs/forms.md

@ -275,10 +275,10 @@ Specifying the `value` prop on a [controlled component](/docs/forms.html#control
The following code demonstrates this. (The input is locked at first but becomes editable after a short delay.)
```javascript
ReactDOM.render(<input value="hi" />, mountNode);
ReactDOM.createRoot(mountNode).render(<input value="hi" />);
setTimeout(function() {
ReactDOM.render(<input value={null} />, mountNode);
ReactDOM.createRoot(mountNode).render(<input value={null} />);
}, 1000);
```

5
content/docs/handling-events.md

@ -84,11 +84,6 @@ class Toggle extends React.Component {
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
```
[**Try it on CodePen**](https://codepen.io/gaearon/pen/xEmzGg?editors=0010)

9
content/docs/hello-world.md

@ -8,11 +8,10 @@ next: introducing-jsx.html
The smallest React example looks like this:
```js
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
```jsx
ReactDOM
.createRoot(document.getElementById('root'))
.render(<h1>Hello, world!</h1>);
```
It displays a heading saying "Hello, world!" on the page.

4
content/docs/hooks-faq.md

@ -148,7 +148,7 @@ We'll test it using React DOM. To make sure that the behavior matches what happe
```js{3,20-22,29-31}
import React from 'react';
import ReactDOM from 'react-dom';
import ReactDOM from 'react-dom/client';
import { act } from 'react-dom/test-utils';
import Counter from './Counter';
@ -167,7 +167,7 @@ afterEach(() => {
it('can render and update a counter', () => {
// Test first render and effect
act(() => {
ReactDOM.render(<Counter />, container);
ReactDOM.createRoot(container).render(<Counter />);
});
const button = container.querySelector('button');
const label = container.querySelector('p');

206
content/docs/hooks-reference.md

@ -24,6 +24,12 @@ If you're new to Hooks, you might want to check out [the overview](/docs/hooks-o
- [`useImperativeHandle`](#useimperativehandle)
- [`useLayoutEffect`](#uselayouteffect)
- [`useDebugValue`](#usedebugvalue)
- [`useDeferredValue`](#usedeferredvalue)
- [`useTransition`](#usetransition)
- [`useId`](#useid)
- [Library Hooks](#library-hooks)
- [`useSyncExternalStore`](#usesyncexternalstore)
- [`useInsertionEffect`](#useinsertioneffect)
## Basic Hooks {#basic-hooks}
@ -138,7 +144,13 @@ Unlike `componentDidMount` and `componentDidUpdate`, the function passed to `use
However, not all effects can be deferred. For example, a DOM mutation that is visible to the user must fire synchronously before the next paint so that the user does not perceive a visual inconsistency. (The distinction is conceptually similar to passive versus active event listeners.) For these types of effects, React provides one additional Hook called [`useLayoutEffect`](#uselayouteffect). It has the same signature as `useEffect`, and only differs in when it is fired.
Although `useEffect` is deferred until after the browser has painted, it's guaranteed to fire before any new renders. React will always flush a previous render's effects before starting a new update.
Additionally, starting in React 18, the function passed to `useEffect` will fire synchronously **before** layout and paint when it's the result of a discrete user input such as a click, or when it's the result of an update wrapped in [`flushSync`](/docs/react-dom.html#flushsync). This behavior allows the result of the effect to be observed by the event system, or by the caller of [`flushSync`](/docs/react-dom.html#flushsync).
> Note
>
> This only affects the timing of when the function passed to `useEffect` is called - updates scheduled inside these effects are still deferred. This is different than [`useLayoutEffect`](#uselayouteffect), which fires the function and processes the updates inside of it immediately.
Even in cases where `useEffect` is deferred until after the browser has painted, it's guaranteed to fire before any new renders. React will always flush a previous render's effects before starting a new update.
#### Conditionally firing an effect {#conditionally-firing-an-effect}
@ -508,3 +520,195 @@ For example a custom Hook that returned a `Date` value could avoid calling the `
```js
useDebugValue(date, date => date.toDateString());
```
### `useDeferredValue` {#usedeferredvalue}
```js
const [deferredValue] = useDeferredValue(value);
```
`useDeferredValue` accepts a value and returns a new copy of the value that will defer to more urgent updates. If the current render is the result of an urgent update, like user input, React will return the previous value and then render the new value after the urgent render has completed.
This hook is similar to user-space hooks which use debouncing or throttling to defer updates. The benefits to using `useDeferredValue` is that React will work on the update as soon as other work finishes (instead of waiting for an arbitrary amount of time), and like [`startTransition`](/docs/react-api.html#starttransition), deferred values can suspend without triggering an unexpected fallback for existing content.
#### Memoizing deferred children {#memoizing-deferred-children}
`useDeferredValue` only defers the value that you pass to it. If you want to prevent a child component from re-rendering during an urgent update, you must also memoize that component with [`React.memo`](/docs/react-api.html#reactmemo) or [`React.useMemo`](/docs/hooks-reference.html#usememo):
```js
function Typeahead() {
const query = useSearchQuery('');
const deferredQuery = useDeferredValue(query);
// Memoizing tells React to only re-render when deferredQuery changes,
// not when query changes.
const suggestions = useMemo(() =>
<SearchSuggestions query={deferredQuery} />,
[deferredQuery]
);
return (
<>
<SearchInput query={query} />
<Suspense fallback="Loading results...">
{suggestions}
</Suspense>
</>
);
}
```
Memoizing the children tells React that it only needs to re-render them when `deferredQuery` changes and not when `query` changes. This caveat is not unique to `useDeferredValue`, and it's the same pattern you would use with similar hooks that use debouncing or throttling.
### `useTransition` {#usetransition}
```js
const [isPending, startTransition] = useTransition();
```
Returns a stateful value for the pending state of the transition, and a function to start it.
`startTransition` lets you mark updates in the provided callback as transitions:
```js
startTransition(() => {
setCount(count + 1);
})
```
`isPending` indicates when a transition is active to show a pending state:
```js
function App() {
const [isPending, startTransition] = useTransition();
const [count, setCount] = useState(0);
function handleClick() {
startTransition(() => {
setCount(c => c + 1);
})
}
return (
<div>
{isPending && <Spinner />}
<button onClick={handleClick}>{count}</button>
</div>
);
}
```
> Note:
>
> Updates in a transition yield to more urgent updates such as clicks.
>
> Updates in a transitions will not show a fallback for re-suspended content. This allows the user to continue interacting with the current content while rendering the update.
### `useId` {#useid}
```js
const id = useId();
```
`useId` is a hook for generating unique IDs that are stable across the server and client, while avoiding hydration mismatches.
For a basic example, pass the `id` directly to the elements that need it:
```js
function Checkbox() {
const id = useId();
return (
<>
<label htmlFor={id}>Do you like React?</label>
<input id={id} type="checkbox" name="react"/>
</>
);
};
```
For multiple IDs in the same component, append a suffix using the same `id`:
```js
function NameFields() {
const id = useId();
return (
<div>
<label htmlFor={id + '-firstName'}>First Name</label>
<div>
<input id={id + '-firstName'} type="text" />
</div>
<label htmlFor={id + '-lastName'}>Last Name</label>
<div>
<input id={id + '-lastName'} type="text" />
</div>
</div>
);
}
```
> Note:
>
> `useId` generates a string that includes the `:` token. This helps ensure that the token is unique, but is not supported in CSS selectors or APIs like `querySelectorAll`.
>
> `useId` supports an `identifierPrefix` to prevent collisions in multi-root apps. To configure, see the options for [`hydrateRoot`](/docs/react-dom-client.html#hydrateroot) and [`ReactDOMServer`](/docs/react-dom-server.html).
## Library Hooks {#library-hooks}
The following Hooks are provided for library authors to integrate libraries deeply into the React model, and are not typically used in application code.
### `useSyncExternalStore` {#usesyncexternalstore}
```js
const state = useSyncExternalStore(subscribe, getSnapshot[, getServerSnapshot]);
```
`useSyncExternalStore` is a hook recommended for reading and subscribing from external data sources in a way that's compatible with concurrent rendering features like selective hydration and time slicing.
This method returns the value of the store and accepts three arguments:
- `subscribe`: function to register a callback that is called whenever the store changes.
- `getSnapshot`: function that returns the current value of the store.
- `getServerSnapshot`: function that returns the snapshot used during server rendering.
The most basic example simply subscribes to the entire store:
```js
const state = useSyncExternalStore(store.subscribe, store.getSnapshot);
```
However, you can also subscribe to a specific field:
```js
const selectedField = useSyncExternalStore(
store.subscribe,
() => store.getSnapshot().selectedField,
);
```
When server rendering, you must serialize the store value used on the server, and provide it to `useSyncExternalStore`. React will use this snapshot during hydration to prevent server mismatches:
```js
const selectedField = useSyncExternalStore(
store.subscribe,
() => store.getSnapshot().selectedField,
() => INITIAL_SERVER_SNAPSHOT.selectedField,
);
```
> Note:
>
> `getSnapshot` must return a cached value. If getSnapshot is called multiple times in a row, it must return the same exact value unless there was a store update in between.
>
> A shim is provided for supporting multiple React versions published as `use-sync-external-store/shim`. This shim will prefer `useSyncExternalStore` when available, and fallback to a user-space implementation when it's not.
>
> As a convenience, we also provide a version of the API with automatic support for memoizing the result of getSnapshot published as `use-sync-external-store/with-selector`.
### `useInsertionEffect` {#useinsertioneffect}
```js
useInsertionEffect(didUpdate);
```
The signature is identical to `useEffect`, but it fires synchronously _before_ all DOM mutations. Use this to inject styles into the DOM before reading layout in [`useLayoutEffect`](#uselayouteffect). Since this hook is limited in scope, this hook does not have access to refs and cannot schedule updates.
> Note:
>
> `useInsertionEffect` should be limited to css-in-js library authors. Prefer [`useEffect`](#useeffect) or [`useLayoutEffect`](#uselayouteffect) instead.

11
content/docs/implementation-notes.md

@ -32,10 +32,11 @@ The reconciler itself doesn't have a public API. [Renderers](/docs/codebase-over
Let's consider the first time you mount a component:
```js
ReactDOM.render(<App />, rootEl);
const root = ReactDOM.createRoot(rootEl);
root.render(<App />);
```
React DOM will pass `<App />` along to the reconciler. Remember that `<App />` is a React element, that is, a description of *what* to render. You can think about it as a plain object:
`root.render` will pass `<App />` along to the reconciler. Remember that `<App />` is a React element, that is, a description of *what* to render. You can think about it as a plain object:
```js
console.log(<App />);
@ -236,9 +237,9 @@ This is working but still far from how the reconciler is really implemented. The
The key feature of React is that you can re-render everything, and it won't recreate the DOM or reset the state:
```js
ReactDOM.render(<App />, rootEl);
root.render(<App />);
// Should reuse the existing DOM:
ReactDOM.render(<App />, rootEl);
root.render(<App />);
```
However, our implementation above only knows how to mount the initial tree. It can't perform updates on it because it doesn't store all the necessary information, such as all the `publicInstance`s, or which DOM `node`s correspond to which components.
@ -412,7 +413,7 @@ If you're struggling to imagine how an internal instance tree is structured in m
<img src="../images/docs/implementation-notes-tree.png" width="500" style="max-width: 100%" alt="React DevTools tree" />
To complete this refactoring, we will introduce a function that mounts a complete tree into a container node, just like `ReactDOM.render()`. It returns a public instance, also like `ReactDOM.render()`:
To complete this refactoring, we will introduce a function that mounts a complete tree into a container node and a public instance:
```js
function mountTree(element, containerNode) {

40
content/docs/integrating-with-other-libraries.md

@ -190,9 +190,9 @@ class Chosen extends React.Component {
## Integrating with Other View Libraries {#integrating-with-other-view-libraries}
React can be embedded into other applications thanks to the flexibility of [`ReactDOM.render()`](/docs/react-dom.html#render).
React can be embedded into other applications thanks to the flexibility of [`createRoot()`](/docs/react-dom-client.html#createRoot).
Although React is commonly used at startup to load a single root React component into the DOM, `ReactDOM.render()` can also be called multiple times for independent parts of the UI which can be as small as a button, or as large as an app.
Although React is commonly used at startup to load a single root React component into the DOM, `root.render()` can also be called multiple times for independent parts of the UI which can be as small as a button, or as large as an app.
In fact, this is exactly how React is used at Facebook. This lets us write applications in React piece by piece, and combine them with our existing server-generated templates and other client-side code.
@ -216,15 +216,9 @@ function Button() {
return <button id="btn">Say Hello</button>;
}
ReactDOM.render(
<Button />,
document.getElementById('container'),
function() {
$('#btn').click(function() {
alert('Hello!');
});
}
);
$('#btn').click(function() {
alert('Hello!');
});
```
From here you could start moving more logic into the component and begin adopting more common React practices. For example, in components it is best not to rely on IDs because the same component can be rendered multiple times. Instead, we will use the [React event system](/docs/handling-events.html) and register the click handler directly on the React `<button>` element:
@ -240,24 +234,19 @@ function HelloButton() {
}
return <Button onClick={handleClick} />;
}
ReactDOM.render(
<HelloButton />,
document.getElementById('container')
);
```
[**Try it on CodePen**](https://codepen.io/gaearon/pen/RVKbvW?editors=1010)
You can have as many such isolated components as you like, and use `ReactDOM.render()` to render them to different DOM containers. Gradually, as you convert more of your app to React, you will be able to combine them into larger components, and move some of the `ReactDOM.render()` calls up the hierarchy.
You can have as many such isolated components as you like, and use `ReactDOM.createRoot()` to render them to different DOM containers. Gradually, as you convert more of your app to React, you will be able to combine them into larger components, and move some of the `ReactDOM.createRoot()` calls up the hierarchy.
### Embedding React in a Backbone View {#embedding-react-in-a-backbone-view}
[Backbone](https://backbonejs.org/) views typically use HTML strings, or string-producing template functions, to create the content for their DOM elements. This process, too, can be replaced with rendering a React component.
Below, we will create a Backbone view called `ParagraphView`. It will override Backbone's `render()` function to render a React `<Paragraph>` component into the DOM element provided by Backbone (`this.el`). Here, too, we are using [`ReactDOM.render()`](/docs/react-dom.html#render):
Below, we will create a Backbone view called `ParagraphView`. It will override Backbone's `render()` function to render a React `<Paragraph>` component into the DOM element provided by Backbone (`this.el`). Here, too, we are using [`ReactDOM.createRoot()`](/docs/react-dom-client.html#createroot):
```js{1,5,8,12}
```js{1,5,8-9,13}
function Paragraph(props) {
return <p>{props.text}</p>;
}
@ -265,11 +254,12 @@ function Paragraph(props) {
const ParagraphView = Backbone.View.extend({
render() {
const text = this.model.get('text');
ReactDOM.render(<Paragraph text={text} />, this.el);
this.root = ReactDOM.createRoot(this.el);
this.root.render(<Paragraph text={text} />);
return this;
},
remove() {
ReactDOM.unmountComponentAtNode(this.el);
this.root.unmount();
Backbone.View.prototype.remove.call(this);
}
});
@ -277,7 +267,7 @@ const ParagraphView = Backbone.View.extend({
[**Try it on CodePen**](https://codepen.io/gaearon/pen/gWgOYL?editors=0010)
It is important that we also call `ReactDOM.unmountComponentAtNode()` in the `remove` method so that React unregisters event handlers and other resources associated with the component tree when it is detached.
It is important that we also call `root.unmount()` in the `remove` method so that React unregisters event handlers and other resources associated with the component tree when it is detached.
When a component is removed *from within* a React tree, the cleanup is performed automatically, but because we are removing the entire tree by hand, we must call this method.
@ -428,10 +418,8 @@ function Example(props) {
}
const model = new Backbone.Model({ firstName: 'Frodo' });
ReactDOM.render(
<Example model={model} />,
document.getElementById('root')
);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Example model={model} />);
```
[**Try it on CodePen**](https://codepen.io/gaearon/pen/PmWwwa?editors=0010)

10
content/docs/introducing-jsx.md

@ -35,11 +35,6 @@ In the example below, we declare a variable called `name` and then use it inside
```js{1,2}
const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;
ReactDOM.render(
element,
document.getElementById('root')
);
```
You can put any valid [JavaScript expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions) inside the curly braces in JSX. For example, `2 + 2`, `user.firstName`, or `formatName(user)` are all valid JavaScript expressions.
@ -61,11 +56,6 @@ const element = (
Hello, {formatName(user)}!
</h1>
);
ReactDOM.render(
element,
document.getElementById('root')
);
```
**[Try it on CodePen](https://codepen.io/gaearon/pen/PGEjdG?editors=1010)**

38
content/docs/lists-and-keys.md

@ -33,13 +33,10 @@ const listItems = numbers.map((number) =>
);
```
We include the entire `listItems` array inside a `<ul>` element, and [render it to the DOM](/docs/rendering-elements.html#rendering-an-element-into-the-dom):
Then, we can include the entire `listItems` array inside a `<ul>` element:
```javascript{2}
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);
<ul>{listItems}</ul>
```
[**Try it on CodePen**](https://codepen.io/gaearon/pen/GjPyQr?editors=0011)
@ -64,10 +61,8 @@ function NumberList(props) {
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<NumberList numbers={numbers} />);
```
When you run this code, you'll be given a warning that a key should be provided for list items. A "key" is a special string attribute you need to include when creating lists of elements. We'll discuss why it's important in the next section.
@ -86,12 +81,6 @@ function NumberList(props) {
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
```
[**Try it on CodePen**](https://codepen.io/gaearon/pen/jrXYRR?editors=0011)
@ -165,12 +154,6 @@ function NumberList(props) {
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
```
**Example: Correct Key Usage**
@ -193,12 +176,6 @@ function NumberList(props) {
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
```
[**Try it on CodePen**](https://codepen.io/gaearon/pen/ZXeOGM?editors=0010)
@ -239,10 +216,9 @@ const posts = [
{id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
{id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
ReactDOM.render(
<Blog posts={posts} />,
document.getElementById('root')
);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Blog posts={posts} />);
```
[**Try it on CodePen**](https://codepen.io/gaearon/pen/NRZYGN?editors=0010)

2
content/docs/nav.yml

@ -92,6 +92,8 @@
title: React.Component
- id: react-dom
title: ReactDOM
- id: react-dom-client
title: ReactDOMClient
- id: react-dom-server
title: ReactDOMServer
- id: dom-elements

3
content/docs/portals.md

@ -146,7 +146,8 @@ function Child() {
);
}
ReactDOM.render(<Parent />, appRoot);
const root = ReactDOM.createRoot(appRoot);
root.render(<Parent />);
```
[**Try it on CodePen**](https://codepen.io/gaearon/pen/jGBWpE)

6
content/docs/react-without-es6.md

@ -216,10 +216,8 @@ var TickTock = createReactClass({
}
});
ReactDOM.render(
<TickTock />,
document.getElementById('example')
);
const root = ReactDOM.createRoot(document.getElementById('example'));
root.render(<TickTock />);
```
If a component is using multiple mixins and several mixins define the same lifecycle method (i.e. several mixins want to do some cleanup when the component is destroyed), all of the lifecycle methods are guaranteed to be called. Methods defined on mixins run in the order mixins were listed, followed by a method call on the component.

18
content/docs/react-without-jsx.md

@ -17,10 +17,8 @@ class Hello extends React.Component {
}
}
ReactDOM.render(
<Hello toWhat="World" />,
document.getElementById('root')
);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Hello toWhat="World" />);
```
can be compiled to this code that does not use JSX:
@ -32,10 +30,8 @@ class Hello extends React.Component {
}
}
ReactDOM.render(
React.createElement(Hello, {toWhat: 'World'}, null),
document.getElementById('root')
);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(React.createElement(Hello, {toWhat: 'World'}, null));
```
If you're curious to see more examples of how JSX is converted to JavaScript, you can try out [the online Babel compiler](babel://jsx-simple-example).
@ -47,10 +43,8 @@ If you get tired of typing `React.createElement` so much, one common pattern is
```js
const e = React.createElement;
ReactDOM.render(
e('div', null, 'Hello World'),
document.getElementById('root')
);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(e('div', null, 'Hello World'));
```
If you use this shorthand form for `React.createElement`, it can be almost as convenient to use React without JSX.

2
content/docs/reference-dom-elements.md

@ -117,7 +117,7 @@ Normally, there is a warning when an element with children is also marked as `co
If you use server-side React rendering, normally there is a warning when the server and the client render different content. However, in some rare cases, it is very hard or impossible to guarantee an exact match. For example, timestamps are expected to differ on the server and on the client.
If you set `suppressHydrationWarning` to `true`, React will not warn you about mismatches in the attributes and the content of that element. It only works one level deep, and is intended to be used as an escape hatch. Don't overuse it. You can read more about hydration in the [`ReactDOM.hydrate()` documentation](/docs/react-dom.html#hydrate).
If you set `suppressHydrationWarning` to `true`, React will not warn you about mismatches in the attributes and the content of that element. It only works one level deep, and is intended to be used as an escape hatch. Don't overuse it. You can read more about hydration in the [`ReactDOM.hydrateRoot()` documentation](/docs/react-dom-client.html#hydrateroot).
### value {#value}

10
content/docs/reference-glossary.md

@ -39,13 +39,9 @@ JSX is a syntax extension to JavaScript. It is similar to a template language, b
React DOM uses camelCase property naming convention instead of HTML attribute names. For example, `tabindex` becomes `tabIndex` in JSX. The attribute `class` is also written as `className` since `class` is a reserved word in JavaScript:
```js
const name = 'Clementine';
ReactDOM.render(
<h1 className="hello">My name is {name}!</h1>,
document.getElementById('root')
);
```
```jsx
<h1 className="hello">My name is Clementine!</h1>
```
## [Elements](/docs/rendering-elements.html) {#elements}

27
content/docs/reference-javascript-environment-requirements.md

@ -6,26 +6,13 @@ category: Reference
permalink: docs/javascript-environment-requirements.html
---
React 16 depends on the collection types [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) and [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set). If you support older browsers and devices which may not yet provide these natively (e.g. IE < 11) or which have non-compliant implementations (e.g. IE 11), consider including a global polyfill in your bundled application, such as [core-js](https://github.com/zloirock/core-js).
React 18 supports all modern browsers (Edge, Firefox, Chrome, Safari, etc).
A polyfilled environment for React 16 using core-js to support older browsers might look like:
If you support older browsers and devices such as Internet Explorer which do not provide modern browser features natively or have non-compliant implementations, consider including a global polyfill in your bundled application.
```js
import 'core-js/es/map';
import 'core-js/es/set';
Here is a list of the modern features React 18 uses:
- [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
- [`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol)
- [`Object.assign`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
```
React also depends on `requestAnimationFrame` (even in test environments).
You can use the [raf](https://www.npmjs.com/package/raf) package to shim `requestAnimationFrame`:
```js
import 'raf/polyfill';
```
The correct polyfill for these features depend on your environment. For many users, you can configure your [Browserlist](https://github.com/browserslist/browserslist) settings. For others, you may need to import polyfills like [`core-js`](https://github.com/zloirock/core-js) directly.

86
content/docs/reference-react-dom-client.md

@ -0,0 +1,86 @@
---
id: react-dom-client
title: ReactDOMClient
layout: docs
category: Reference
permalink: docs/react-dom-client.html
---
The `react-dom/client` package provides client-specific methods used for initializing an app on the client. Most of your components should not need to use this module.
```js
import * as ReactDOM from 'react-dom/client';
```
If you use ES5 with npm, you can write:
```js
var ReactDOM = require('react-dom/client');
```
## Overview {#overview}
The following methods can be used in client environments:
- [`createRoot()`](#createroot)
- [`hydrateRoot()`](#hydrateroot)
### Browser Support {#browser-support}
React supports all modern browsers, although [some polyfills are required](/docs/javascript-environment-requirements.html) for older versions.
> Note
>
> We do not support older browsers that don't support ES5 methods or microtasks such as Internet Explorer. You may find that your apps do work in older browsers if polyfills such as [es5-shim and es5-sham](https://github.com/es-shims/es5-shim) are included in the page, but you're on your own if you choose to take this path.
## Reference {#reference}
### `createRoot()` {#createroot}
```javascript
createRoot(container[, options]);
```
Create a React root for the supplied `container` and return the root. The root can be used to render a React element into the DOM with `render`:
```javascript
const root = createRoot(container);
root.render(element);
```
`createRoot` accepts two options:
- `onRecoverableError`: optional callback called when React automatically recovers from errors.
- `identifierPrefix`: optional prefix React uses for ids generated by `React.useId`. Useful to avoid conflicts when using multiple roots on the same page. Must be the same prefix used on the server.
The root can also be unmounted with `unmount`:
```javascript
root.unmount();
```
> Note:
>
> `createRoot()` controls the contents of the container node you pass in. Any existing DOM elements inside are replaced when render is called. Later calls use React’s DOM diffing algorithm for efficient updates.
>
> `createRoot()` does not modify the container node (only modifies the children of the container). It may be possible to insert a component to an existing DOM node without overwriting the existing children.
>
> Using `createRoot()` to hydrate a server-rendered container is not supported. Use [`hydrateRoot()`](#hydrateroot) instead.
* * *
### `hydrateRoot()` {#hydrateroot}
```javascript
hydrateRoot(element, container[, options])
```
Same as [`createRoot()`](#createroot), but is used to hydrate a container whose HTML contents were rendered by [`ReactDOMServer`](/docs/react-dom-server.html). React will attempt to attach event listeners to the existing markup.
`hydrateRoot` accepts two options:
- `onRecoverableError`: optional callback called when React automatically recovers from errors.
- `identifierPrefix`: optional prefix React uses for ids generated by `React.useId`. Useful to avoid conflicts when using multiple roots on the same page. Must be the same prefix used on the server.
> Note
>
> React expects that the rendered content is identical between the server and the client. It can patch up differences in text content, but you should treat mismatches as bugs and fix them. In development mode, React warns about mismatches during hydration. There are no guarantees that attribute differences will be patched up in case of mismatches. This is important for performance reasons because in most apps, mismatches are rare, and so validating all markup would be prohibitively expensive.

91
content/docs/reference-react-dom-server.md

@ -24,7 +24,9 @@ The following methods can be used in both the server and browser environments:
These additional methods depend on a package (`stream`) that is **only available on the server**, and won't work in the browser.
- [`renderToNodeStream()`](#rendertonodestream)
- [`renderToPipeableStream()`](#rendertopipeablestream)
- [`renderToReadableStream()`](#rendertoreadablestream)
- [`renderToNodeStream()`](#rendertonodestream) (Deprecated)
- [`renderToStaticNodeStream()`](#rendertostaticnodestream)
* * *
@ -39,7 +41,7 @@ ReactDOMServer.renderToString(element)
Render a React element to its initial HTML. React will return an HTML string. You can use this method to generate HTML on the server and send the markup down on the initial request for faster page loads and to allow search engines to crawl your pages for SEO purposes.
If you call [`ReactDOM.hydrate()`](/docs/react-dom.html#hydrate) on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.
If you call [`ReactDOM.hydrateRoot()`](/docs/react-dom-client.html#hydrateroot) on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.
* * *
@ -51,11 +53,88 @@ ReactDOMServer.renderToStaticMarkup(element)
Similar to [`renderToString`](#rendertostring), except this doesn't create extra DOM attributes that React uses internally, such as `data-reactroot`. This is useful if you want to use React as a simple static page generator, as stripping away the extra attributes can save some bytes.
If you plan to use React on the client to make the markup interactive, do not use this method. Instead, use [`renderToString`](#rendertostring) on the server and [`ReactDOM.hydrate()`](/docs/react-dom.html#hydrate) on the client.
If you plan to use React on the client to make the markup interactive, do not use this method. Instead, use [`renderToString`](#rendertostring) on the server and [`ReactDOM.hydrateRoot()`](/docs/react-dom-client.html#hydrateroot) on the client.
* * *
### `renderToNodeStream()` {#rendertonodestream}
### `renderToPipeableStream()` {#rendertopipeablestream}
```javascript
ReactDOMServer.renderToPipeableStream(element, options)
```
Render a React element to its initial HTML. Returns a [Control object](https://github.com/facebook/react/blob/3f8990898309c61c817fbf663f5221d9a00d0eaa/packages/react-dom/src/server/ReactDOMFizzServerNode.js#L49-L54) that allows you to pipe the output or abort the request. Fully supports Suspense and streaming of HTML with "delayed" content blocks "popping in" later through javascript execution. [Read more](https://github.com/reactwg/react-18/discussions/37)
If you call [`ReactDOM.hydrateRoot()`](/docs/react-dom-client.html#hydrateroot) on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.
> Note:
>
> This is a Node.js specific API and modern server environments should use renderToReadableStream instead.
>
```
const {pipe, abort} = renderToPipeableStream(
<App />,
{
onAllReady() {
res.statusCode = 200;
res.setHeader('Content-type', 'text/html');
pipe(res);
},
onShellError(x) {
res.statusCode = 500;
res.send(
'<!doctype html><p>Loading...</p><script src="clientrender.js"></script>'
);
}
}
);
```
* * *
### `renderToReadableStream()` {#rendertoreadablestream}
```javascript
ReactDOMServer.renderToReadableStream(element, options);
```
Streams a React element to its initial HTML. Returns a [Readable Stream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream). Fully supports Suspense and streaming of HTML. [Read more](https://github.com/reactwg/react-18/discussions/127)
If you call [`ReactDOM.hydrateRoot()`](/docs/react-dom-client.html#hydrateroot) on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.
```
let controller = new AbortController();
try {
let stream = await renderToReadableStream(
<html>
<body>Success</body>
</html>,
{
signal: controller.signal,
}
);
// This is to wait for all suspense boundaries to be ready. You can uncomment
// this line if you don't want to stream to the client
// await stream.allReady;
return new Response(stream, {
headers: {'Content-Type': 'text/html'},
});
} catch (error) {
return new Response(
'<!doctype html><p>Loading...</p><script src="clientrender.js"></script>',
{
status: 500,
headers: {'Content-Type': 'text/html'},
}
);
}
```
* * *
### `renderToNodeStream()` {#rendertonodestream} (Deprecated)
```javascript
ReactDOMServer.renderToNodeStream(element)
@ -63,7 +142,7 @@ ReactDOMServer.renderToNodeStream(element)
Render a React element to its initial HTML. Returns a [Readable stream](https://nodejs.org/api/stream.html#stream_readable_streams) that outputs an HTML string. The HTML output by this stream is exactly equal to what [`ReactDOMServer.renderToString`](#rendertostring) would return. You can use this method to generate HTML on the server and send the markup down on the initial request for faster page loads and to allow search engines to crawl your pages for SEO purposes.
If you call [`ReactDOM.hydrate()`](/docs/react-dom.html#hydrate) on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.
If you call [`ReactDOM.hydrateRoot()`](/docs/react-dom-client.html#hydrateroot) on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.
> Note:
>
@ -83,7 +162,7 @@ Similar to [`renderToNodeStream`](#rendertonodestream), except this doesn't crea
The HTML output by this stream is exactly equal to what [`ReactDOMServer.renderToStaticMarkup`](#rendertostaticmarkup) would return.
If you plan to use React on the client to make the markup interactive, do not use this method. Instead, use [`renderToNodeStream`](#rendertonodestream) on the server and [`ReactDOM.hydrate()`](/docs/react-dom.html#hydrate) on the client.
If you plan to use React on the client to make the markup interactive, do not use this method. Instead, use [`renderToNodeStream`](#rendertonodestream) on the server and [`ReactDOM.hydrateRoot()`](/docs/react-dom-client.html#hydrateroot) on the client.
> Note:
>

98
content/docs/reference-react-dom.md

@ -6,36 +6,84 @@ category: Reference
permalink: docs/react-dom.html
---
If you load React from a `<script>` tag, these top-level APIs are available on the `ReactDOM` global. If you use ES6 with npm, you can write `import ReactDOM from 'react-dom'`. If you use ES5 with npm, you can write `var ReactDOM = require('react-dom')`.
The `react-dom` package provides DOM-specific methods that can be used at the top level of your app and as an escape hatch to get outside the React model if you need to.
```js
import * as ReactDOM from 'react-dom';
```
If you use ES5 with npm, you can write:
```js
var ReactDOM = require('react-dom');
```
The `react-dom` package also provides modules specific to client and server apps:
- [`react-dom/client`](/docs/react-dom-client.html)
- [`react-dom/server`](/docs/react-dom-server.html)
## Overview {#overview}
The `react-dom` package provides DOM-specific methods that can be used at the top level of your app and as an escape hatch to get outside of the React model if you need to. Most of your components should not need to use this module.
The `react-dom` package exports these methods:
- [`createPortal()`](#createportal)
- [`flushSync()`](#flushsync)
These `react-dom` methods are also exported, but are considered legacy:
- [`render()`](#render)
- [`hydrate()`](#hydrate)
- [`unmountComponentAtNode()`](#unmountcomponentatnode)
- [`findDOMNode()`](#finddomnode)
- [`createPortal()`](#createportal)
- [`unmountComponentAtNode()`](#unmountcomponentatnode)
> Note:
>
> Both `render` and `hydrate` have been replaced with new [client methods](/docs/react-dom-client.html) in React 18. These methods will warn that your app will behave as if it's running React 17 (learn more [here](https://reactjs.org/link/switch-to-createroot)).
### Browser Support {#browser-support}
React supports all popular browsers, including Internet Explorer 9 and above, although [some polyfills are required](/docs/javascript-environment-requirements.html) for older browsers such as IE 9 and IE 10.
React supports all modern browsers, although [some polyfills are required](/docs/javascript-environment-requirements.html) for older versions.
> Note
>
> We don't support older browsers that don't support ES5 methods, but you may find that your apps do work in older browsers if polyfills such as [es5-shim and es5-sham](https://github.com/es-shims/es5-shim) are included in the page. You're on your own if you choose to take this path.
* * *
> We do not support older browsers that don't support ES5 methods or microtasks such as Internet Explorer. You may find that your apps do work in older browsers if polyfills such as [es5-shim and es5-sham](https://github.com/es-shims/es5-shim) are included in the page, but you're on your own if you choose to take this path.
## Reference {#reference}
### `render()` {#render}
### `createPortal()` {#createportal}
```javascript
ReactDOM.render(element, container[, callback])
createPortal(child, container)
```
Creates a portal. Portals provide a way to [render children into a DOM node that exists outside the hierarchy of the DOM component](/docs/portals.html).
### `flushSync()` {#flushsync}
```javascript
flushSync(callback)
```
Force React to flush any updates inside the provided callback synchronously. This method is useful for being able to read the result of those updates immediately.
> Note:
>
> `flushSync` can have a significant impact on performance. Use sparingly.
>
> `flushSync` may force pending Suspense boundaries to show their `fallback` state.
>
> `flushSync` may also run pending effects and synchronously apply any updates they contain before returning.
>
> `flushSync` may also flush updates outside the callback when necessary to flush the updates inside the callback. For example, if there are pending updates from a click, React may flush those before flushing the updates inside the callback.
## Legacy Reference {#legacy-reference}
### `render()` {#render}
```javascript
render(element, container[, callback])
```
> Note:
>
> `render` has been replaced with `createRoot` in React 18. See [createRoot](/docs/react-dom-client.html#createroot) for more info.
Render a React element into the DOM in the supplied `container` and return a [reference](/docs/more-about-refs.html) to the component (or returns `null` for [stateless components](/docs/components-and-props.html#function-and-class-components)).
If the React element was previously rendered into `container`, this will perform an update on it and only mutate the DOM as necessary to reflect the latest React element.
@ -44,24 +92,28 @@ If the optional callback is provided, it will be executed after the component is
> Note:
>
> `ReactDOM.render()` controls the contents of the container node you pass in. Any existing DOM elements inside are replaced when first called. Later calls use React’s DOM diffing algorithm for efficient updates.
> `render()` controls the contents of the container node you pass in. Any existing DOM elements inside are replaced when first called. Later calls use React’s DOM diffing algorithm for efficient updates.
>
> `ReactDOM.render()` does not modify the container node (only modifies the children of the container). It may be possible to insert a component to an existing DOM node without overwriting the existing children.
> `render()` does not modify the container node (only modifies the children of the container). It may be possible to insert a component to an existing DOM node without overwriting the existing children.
>
> `ReactDOM.render()` currently returns a reference to the root `ReactComponent` instance. However, using this return value is legacy
> `render()` currently returns a reference to the root `ReactComponent` instance. However, using this return value is legacy
> and should be avoided because future versions of React may render components asynchronously in some cases. If you need a reference to the root `ReactComponent` instance, the preferred solution is to attach a
> [callback ref](/docs/refs-and-the-dom.html#callback-refs) to the root element.
>
> Using `ReactDOM.render()` to hydrate a server-rendered container is deprecated and will be removed in React 17. Use [`hydrate()`](#hydrate) instead.
> Using `render()` to hydrate a server-rendered container is deprecated. Use [`hydrateRoot()`](#hydrateroot) instead.
* * *
### `hydrate()` {#hydrate}
```javascript
ReactDOM.hydrate(element, container[, callback])
hydrate(element, container[, callback])
```
> Note:
>
> `hydrate` has been replaced with `hydrateRoot` in React 18. See [hydrateRoot](/docs/react-dom-client.html#hydrateroot) for more info.
Same as [`render()`](#render), but is used to hydrate a container whose HTML contents were rendered by [`ReactDOMServer`](/docs/react-dom-server.html). React will attempt to attach event listeners to the existing markup.
React expects that the rendered content is identical between the server and the client. It can patch up differences in text content, but you should treat mismatches as bugs and fix them. In development mode, React warns about mismatches during hydration. There are no guarantees that attribute differences will be patched up in case of mismatches. This is important for performance reasons because in most apps, mismatches are rare, and so validating all markup would be prohibitively expensive.
@ -77,9 +129,13 @@ Remember to be mindful of user experience on slow connections. The JavaScript co
### `unmountComponentAtNode()` {#unmountcomponentatnode}
```javascript
ReactDOM.unmountComponentAtNode(container)
unmountComponentAtNode(container)
```
> Note:
>
> `unmountComponentAtNode` has been replaced with `root.unmount()` in React 18. See [createRoot](/docs/react-dom-client.html#createroot) for more info.
Remove a mounted React component from the DOM and clean up its event handlers and state. If no component was mounted in the container, calling this function does nothing. Returns `true` if a component was unmounted and `false` if there was no component to unmount.
* * *
@ -91,7 +147,7 @@ Remove a mounted React component from the DOM and clean up its event handlers an
> `findDOMNode` is an escape hatch used to access the underlying DOM node. In most cases, use of this escape hatch is discouraged because it pierces the component abstraction. [It has been deprecated in `StrictMode`.](/docs/strict-mode.html#warning-about-deprecated-finddomnode-usage)
```javascript
ReactDOM.findDOMNode(component)
findDOMNode(component)
```
If this component has been mounted into the DOM, this returns the corresponding native browser DOM element. This method is useful for reading values out of the DOM, such as form field values and performing DOM measurements. **In most cases, you can attach a ref to the DOM node and avoid using `findDOMNode` at all.**
@ -104,11 +160,3 @@ When a component renders to `null` or `false`, `findDOMNode` returns `null`. Whe
> `findDOMNode` cannot be used on function components.
* * *
### `createPortal()` {#createportal}
```javascript
ReactDOM.createPortal(child, container)
```
Creates a portal. Portals provide a way to [render children into a DOM node that exists outside the hierarchy of the DOM component](/docs/portals.html).

48
content/docs/reference-react.md

@ -65,6 +65,13 @@ Suspense lets components "wait" for something before rendering. Today, Suspense
- [`React.lazy`](#reactlazy)
- [`React.Suspense`](#reactsuspense)
### Transitions {#transitions}
*Transitions* are a new concurrent feature introduced in React 18. They allow you to mark updates as transitions, which tells React that they can be interrupted and avoid going back to Suspense fallbacks for already visible content.
- [`React.startTransition`](#starttransition)
- [`React.useTransition`](/docs/hooks-reference.html#usetransition)
### Hooks {#hooks}
*Hooks* are a new addition in React 16.8. They let you use state and other React features without writing a class. Hooks have a [dedicated docs section](/docs/hooks-intro.html) and a separate API reference:
@ -81,6 +88,12 @@ Suspense lets components "wait" for something before rendering. Today, Suspense
- [`useImperativeHandle`](/docs/hooks-reference.html#useimperativehandle)
- [`useLayoutEffect`](/docs/hooks-reference.html#uselayouteffect)
- [`useDebugValue`](/docs/hooks-reference.html#usedebugvalue)
- [`useDeferredValue`](/docs/hooks-reference.html#usedeferredvalue)
- [`useTransition`](/docs/hooks-reference.html#usetransition)
- [`useId`](/docs/hooks-reference.html#useid)
- [Library Hooks](/docs/hooks-reference.html#library-hooks)
- [`useSyncExternalStore`](/docs/hooks-reference.html#usesyncexternalstore)
- [`useInsertionEffect`](/docs/hooks-reference.html#useinsertioneffect)
* * *
@ -329,13 +342,11 @@ const SomeComponent = React.lazy(() => import('./SomeComponent'));
Note that rendering `lazy` components requires that there's a `<React.Suspense>` component higher in the rendering tree. This is how you specify a loading indicator.
> **Note**
>
> Using `React.lazy`with dynamic import requires Promises to be available in the JS environment. This requires a polyfill on IE11 and below.
### `React.Suspense` {#reactsuspense}
`React.Suspense` lets you specify the loading indicator in case some components in the tree below it are not yet ready to render. Today, lazy loading components is the **only** use case supported by `<React.Suspense>`:
`React.Suspense` lets you specify the loading indicator in case some components in the tree below it are not yet ready to render. In the future we plan to let `Suspense` handle more scenarios such as data fetching. You can read about this in [our roadmap](/blog/2018/11/27/react-16-roadmap.html).
Today, lazy loading components is the **only** use case supported by `<React.Suspense>`:
```js
// This component is loaded dynamically
@ -355,8 +366,29 @@ function MyComponent() {
It is documented in our [code splitting guide](/docs/code-splitting.html#reactlazy). Note that `lazy` components can be deep inside the `Suspense` tree -- it doesn't have to wrap every one of them. The best practice is to place `<Suspense>` where you want to see a loading indicator, but to use `lazy()` wherever you want to do code splitting.
While this is not supported today, in the future we plan to let `Suspense` handle more scenarios such as data fetching. You can read about this in [our roadmap](/blog/2018/11/27/react-16-roadmap.html).
> Note
>
> For content that is already shown to the user, switching back to a loading indicator can be disorienting. It is sometimes better to show the "old" UI while the new UI is being prepared. To do this, you can use the new transition APIs [`startTransition`](#starttransition) and [`useTransition`](/docs/hooks-reference.html#usetransition) to mark updates as transitions and avoid unexpected fallbacks.
#### `React.Suspense` in Server Side Rendering {#reactsuspense-in-server-side-rendering}
During server side rendering Suspense Boundaries allow you to flush your application in smaller chunks by suspending.
When a component suspends we schedule a low priority task to render the closest Suspense boundary's fallback. If the component unsuspends before we flush the fallback then we send down the actual content and throw away the fallback.
>Note:
#### `React.Suspense` during hydration {#reactsuspense-during-hydration}
Suspense boundaries depend on their parent boundaries being hydrated before they can hydrate, but they can hydrate independently from sibling boundaries. Events on a boundary before its hydrated will cause the boundary to hydrate at
a higher priority than neighboring boundaries. [Read more](https://github.com/reactwg/react-18/discussions/130)
### `React.startTransition` {#starttransition}
```js
React.startTransition(callback)
```
`React.startTransition` lets you mark updates inside the provided callback as transitions. This method is designed to be used when [`React.useTransition`](/docs/hooks-reference.html#usetransition) is not available.
> Note:
>
> Updates in a transition yield to more urgent updates such as clicks.
>
> Updates in a transitions will not show a fallback for re-suspended content, allowing the user to continue interacting while rendering the update.
>
>`React.lazy()` and `<React.Suspense>` are not yet supported by `ReactDOMServer`. This is a known limitation that will be resolved in the future.
> `React.startTransition` does not provide an `isPending` flag. To track the pending status of a transition see [`React.useTransition`](/docs/hooks-reference.html#usetransition).

8
content/docs/rendering-elements.md

@ -34,7 +34,7 @@ We call this a "root" DOM node because everything inside it will be managed by R
Applications built with just React usually have a single root DOM node. If you are integrating React into an existing app, you may have as many isolated root DOM nodes as you like.
To render a React element into a root DOM node, pass both to [`ReactDOM.render()`](/docs/react-dom.html#render):
To render a React element, first pass the DOM element to [`ReactDOM.createRoot()`](/docs/react-dom-client.html#createroot), then pass the React element to `root.render()`:
`embed:rendering-elements/render-an-element.js`
@ -46,7 +46,7 @@ It displays "Hello, world" on the page.
React elements are [immutable](https://en.wikipedia.org/wiki/Immutable_object). Once you create an element, you can't change its children or attributes. An element is like a single frame in a movie: it represents the UI at a certain point in time.
With our knowledge so far, the only way to update the UI is to create a new element, and pass it to [`ReactDOM.render()`](/docs/react-dom.html#render).
With our knowledge so far, the only way to update the UI is to create a new element, and pass it to `root.render()`.
Consider this ticking clock example:
@ -54,11 +54,11 @@ Consider this ticking clock example:
**[Try it on CodePen](https://codepen.io/gaearon/pen/gwoJZk?editors=1010)**
It calls [`ReactDOM.render()`](/docs/react-dom.html#render) every second from a [`setInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval) callback.
It calls [`root.render()`](/docs/react-dom.html#render) every second from a [`setInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval) callback.
>**Note:**
>
>In practice, most React apps only call [`ReactDOM.render()`](/docs/react-dom.html#render) once. In the next sections we will learn how such code gets encapsulated into [stateful components](/docs/state-and-lifecycle.html).
>In practice, most React apps only call `root.render()` once. In the next sections we will learn how such code gets encapsulated into [stateful components](/docs/state-and-lifecycle.html).
>
>We recommend that you don't skip topics because they build on each other.

49
content/docs/state-and-lifecycle.md

@ -10,9 +10,11 @@ next: handling-events.html
This page introduces the concept of state and lifecycle in a React component. You can find a [detailed component API reference here](/docs/react-component.html).
Consider the ticking clock example from [one of the previous sections](/docs/rendering-elements.html#updating-the-rendered-element). In [Rendering Elements](/docs/rendering-elements.html#rendering-an-element-into-the-dom), we have only learned one way to update the UI. We call `ReactDOM.render()` to change the rendered output:
Consider the ticking clock example from [one of the previous sections](/docs/rendering-elements.html#updating-the-rendered-element). In [Rendering Elements](/docs/rendering-elements.html#rendering-an-element-into-the-dom), we have only learned one way to update the UI. We call `root.render()` to change the rendered output:
```js{8-11}
```js{10}
const root = ReactDOM.createRoot(document.getElementById('root'));
function tick() {
const element = (
<div>
@ -20,10 +22,7 @@ function tick() {
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('root')
);
root.render(element);
}
setInterval(tick, 1000);
@ -35,7 +34,9 @@ In this section, we will learn how to make the `Clock` component truly reusable
We can start by encapsulating how the clock looks:
```js{3-6,12}
```js{5-8,13}
const root = ReactDOM.createRoot(document.getElementById('root'));
function Clock(props) {
return (
<div>
@ -46,10 +47,7 @@ function Clock(props) {
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
root.render(<Clock date={new Date()} />);
}
setInterval(tick, 1000);
@ -62,10 +60,7 @@ However, it misses a crucial requirement: the fact that the `Clock` sets up a ti
Ideally we want to write this once and have the `Clock` update itself:
```js{2}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
root.render(<Clock />);
```
To implement this, we need to add "state" to the `Clock` component.
@ -158,10 +153,7 @@ Class components should always call the base constructor with `props`.
3) Remove the `date` prop from the `<Clock />` element:
```js{2}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
root.render(<Clock />);
```
We will later add the timer code back to the component itself.
@ -185,10 +177,8 @@ class Clock extends React.Component {
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Clock />);
```
[**Try it on CodePen**](https://codepen.io/gaearon/pen/KgQpJd?editors=0010)
@ -294,10 +284,8 @@ class Clock extends React.Component {
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Clock />);
```
[**Try it on CodePen**](https://codepen.io/gaearon/pen/amqdNA?editors=0010)
@ -306,7 +294,7 @@ Now the clock ticks every second.
Let's quickly recap what's going on and the order in which the methods are called:
1) When `<Clock />` is passed to `ReactDOM.render()`, React calls the constructor of the `Clock` component. Since `Clock` needs to display the current time, it initializes `this.state` with an object including the current time. We will later update this state.
1) When `<Clock />` is passed to `root.render()`, React calls the constructor of the `Clock` component. Since `Clock` needs to display the current time, it initializes `this.state` with an object including the current time. We will later update this state.
2) React then calls the `Clock` component's `render()` method. This is how React learns what should be displayed on the screen. React then updates the DOM to match the `Clock`'s render output.
@ -447,11 +435,6 @@ function App() {
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
```
[**Try it on CodePen**](https://codepen.io/gaearon/pen/vXdGmd?editors=0010)

49
content/docs/strict-mode.md

@ -21,6 +21,7 @@ In the above example, strict mode checks will *not* be run against the `Header`
* [Warning about deprecated findDOMNode usage](#warning-about-deprecated-finddomnode-usage)
* [Detecting unexpected side effects](#detecting-unexpected-side-effects)
* [Detecting legacy context API](#detecting-legacy-context-api)
* [Detecting unsafe effects](#detecting-unsafe-effects)
Additional functionality will be added with future releases of React.
@ -127,3 +128,51 @@ The legacy context API is error-prone, and will be removed in a future major ver
![](../images/blog/warn-legacy-context-in-strict-mode.png)
Read the [new context API documentation](/docs/context.html) to help migrate to the new version.
### Ensuring reusable state {#ensuring-reusable-state}
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 support remounting trees using the same component state used before unmounting.
This feature will give React 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 do not properly clean up subscriptions in the destroy callback, or implicitly 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.
To demonstrate the development behavior you'll see in Strict Mode with this feature, consider what happens when React mounts a new component. Without this change, when a component mounts, React creates the effects:
```
* React mounts the component.
* Layout effects are created.
* Effects are created.
```
With Strict Mode starting in React 18, whenever a component mounts in development, React will simulate immediately unmounting and remounting the component:
```
* React mounts the component.
* Layout effects are created.
* Effect effects are created.
* React simulates effects being destroyed on a mounted component.
* Layout effects are destroyed.
* Effects are destroyed.
* React simulates effects being re-created on a mounted component.
* Layout effects are created
* Effect setup code runs
```
On the second mount, React will restore the state from the first mount. This feature simulates user behavior such as a user tabbing away from a screen and back, ensuring that code will properly handle state restoration.
When the component unmounts, effects are destroyed as normal:
```
* React unmounts the component.
* Layout effects are destroyed.
* Effect effects are destroyed.
```
> Note:
>
> This only applies to development mode, _production behavior is unchanged_.
For help supporting common issues, see:
- [How to support Reusable State in Effects](https://github.com/reactwg/react-18/discussions/18)

2
content/docs/testing-recipes.md

@ -605,7 +605,7 @@ It's typically better to make more specific assertions than to use snapshots. Th
### Multiple Renderers {#multiple-renderers}
In rare cases, you may be running a test on a component that uses multiple renderers. For example, you may be running snapshot tests on a component with `react-test-renderer`, that internally uses `ReactDOM.render` inside a child component to render some content. In this scenario, you can wrap updates with `act()`s corresponding to their renderers.
In rare cases, you may be running a test on a component that uses multiple renderers. For example, you may be running snapshot tests on a component with `react-test-renderer`, that internally uses `render` from `react-dom` inside a child component to render some content. In this scenario, you can wrap updates with `act()`s corresponding to their renderers.
```jsx
import { act as domAct } from "react-dom/test-utils";

2
content/docs/thinking-in-react.md

@ -70,7 +70,7 @@ To build a static version of your app that renders your data model, you'll want
You can build top-down or bottom-up. That is, you can either start with building the components higher up in the hierarchy (i.e. starting with `FilterableProductTable`) or with the ones lower in it (`ProductRow`). In simpler examples, it's usually easier to go top-down, and on larger projects, it's easier to go bottom-up and write tests as you build.
At the end of this step, you'll have a library of reusable components that render your data model. The components will only have `render()` methods since this is a static version of your app. The component at the top of the hierarchy (`FilterableProductTable`) will take your data model as a prop. If you make a change to your underlying data model and call `ReactDOM.render()` again, the UI will be updated. You can see how your UI is updated and where to make changes. React's **one-way data flow** (also called *one-way binding*) keeps everything modular and fast.
At the end of this step, you'll have a library of reusable components that render your data model. The components will only have `render()` methods since this is a static version of your app. The component at the top of the hierarchy (`FilterableProductTable`) will take your data model as a prop. If you make a change to your underlying data model and call `root.render()` again, the UI will be updated. You can see how your UI is updated and where to make changes. React's **one-way data flow** (also called *one-way binding*) keeps everything modular and fast.
Refer to the [React docs](/docs/getting-started.html) if you need help executing this step.

6
content/docs/typechecking-with-proptypes.md

@ -173,10 +173,8 @@ Greeting.defaultProps = {
};
// Renders "Hello, Stranger":
ReactDOM.render(
<Greeting />,
document.getElementById('example')
);
const root = ReactDOM.createRoot(document.getElementById('example'));
root.render(<Greeting />);
```
If you are using a Babel transform like [plugin-proposal-class-properties](https://babeljs.io/docs/en/babel-plugin-proposal-class-properties/) (previously _plugin-transform-class-properties_), you can also declare `defaultProps` as static property within a React component class. This syntax has not yet been finalized though and will require a compilation step to work within a browser. For more information, see the [class fields proposal](https://github.com/tc39/proposal-class-fields).

3
content/docs/web-components.md

@ -50,7 +50,8 @@ class XSearch extends HTMLElement {
const name = this.getAttribute('name');
const url = 'https://www.google.com/search?q=' + encodeURIComponent(name);
ReactDOM.render(<a href={url}>{name}</a>, mountPoint);
const root = ReactDOM.createRoot(mountPoint);
root.render(<a href={url}>{name}</a>);
}
}
customElements.define('x-search', XSearch);

5
content/home/examples/a-component-using-external-plugins.js

@ -36,7 +36,4 @@ class MarkdownEditor extends React.Component {
}
}
ReactDOM.render(
<MarkdownEditor />,
document.getElementById('markdown-example')
);
root.render(<MarkdownEditor />);

11
content/home/examples/a-simple-component.js

@ -1,14 +1,7 @@
class HelloMessage extends React.Component {
render() {
return (
<div>
Hello {this.props.name}
</div>
);
return <div>Hello {this.props.name}</div>;
}
}
ReactDOM.render(
<HelloMessage name="Taylor" />,
document.getElementById('hello-example')
);
root.render(<HelloMessage name="Taylor" />);

5
content/home/examples/a-stateful-component.js

@ -27,7 +27,4 @@ class Timer extends React.Component {
}
}
ReactDOM.render(
<Timer />,
document.getElementById('timer-example')
);
root.render(<Timer />);

5
content/home/examples/an-application.js

@ -60,7 +60,4 @@ class TodoList extends React.Component {
}
}
ReactDOM.render(
<TodoApp />,
document.getElementById('todos-example')
);
root.render(<TodoApp />);

23
content/versions.yml

@ -1,5 +1,8 @@
- title: '18.0.0'
changelog: https://github.com/facebook/react/blob/main/CHANGELOG.md
- title: '17.0.2'
changelog: https://github.com/facebook/react/blob/main/CHANGELOG.md#1702-march-22-2021
url: https://17.reactjs.org
- title: '17.0.1'
changelog: https://github.com/facebook/react/blob/main/CHANGELOG.md#1701-october-22-2020
- title: '17.0.0'
@ -23,42 +26,22 @@
- title: '16.9'
changelog: https://github.com/facebook/react/blob/main/CHANGELOG.md#1690-august-8-2019
- title: '16.8'
path: /version/16.8
changelog: https://github.com/facebook/react/blob/main/CHANGELOG.md#1680-february-6-2019
url: https://5d4b5feba32acd0008d0df98--reactjs.netlify.com/
- title: '16.7'
path: /version/16.7
changelog: https://github.com/facebook/react/blob/main/CHANGELOG.md#1670-december-19-2018
url: https://5c54aa429e16c80007af3cd2--reactjs.netlify.com/
- title: '16.6'
path: /version/16.6
changelog: https://github.com/facebook/react/blob/main/CHANGELOG.md#1660-october-23-2018
url: https://5c11762d4be4d10008916ab1--reactjs.netlify.com/
- title: '16.5'
path: /version/16.5
changelog: https://github.com/facebook/react/blob/main/CHANGELOG.md#1650-september-5-2018
url: https://5bcf5863c6aed64970d6de5b--reactjs.netlify.com/
- title: '16.4'
path: /version/16.4
changelog: https://github.com/facebook/react/blob/main/CHANGELOG.md#1640-may-23-2018
url: https://5b90c17ac9659241e7f4c938--reactjs.netlify.com
- title: '16.3'
path: /version/16.3
url: https://5b05c94e0733d530fd1fafe0--reactjs.netlify.com
changelog: https://github.com/facebook/react/blob/main/CHANGELOG.md#1632-april-16-2018
- title: '16.2'
path: /version/16.2
url: https://5abc31d8be40f1556f06c4be--reactjs.netlify.com
changelog: https://github.com/facebook/react/blob/main/CHANGELOG.md#1620-november-28-2017
- title: '16.1'
path: /version/16.1
url: https://5a1dbcf14c4b93299e65b9a9--reactjs.netlify.com
changelog: https://github.com/facebook/react/blob/main/CHANGELOG.md#1611-november-13-2017
- title: '16.0'
path: /version/16.0
url: https://5a046bf5a6188f4b8fa4938a--reactjs.netlify.com
changelog: https://github.com/facebook/react/blob/main/CHANGELOG.md#1600-september-26-2017
- title: '15.6'
path: /version/15.6
url: https://react-legacy.netlify.com
changelog: https://github.com/facebook/react/blob/main/CHANGELOG.md#1562-september-25-2017

5
examples/rendering-elements/render-an-element.js

@ -1,2 +1,5 @@
const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));
const root = ReactDOM.createRoot(
document.getElementById('root')
);
root.render(element);

6
examples/rendering-elements/update-rendered-element.js

@ -1,3 +1,7 @@
const root = ReactDOM.createRoot(
document.getElementById('root')
);
function tick() {
const element = (
<div>
@ -6,7 +10,7 @@ function tick() {
</div>
);
// highlight-next-line
ReactDOM.render(element, document.getElementById('root'));
root.render(element);
}
setInterval(tick, 1000);

11
src/components/CodeEditor/CodeEditor.js

@ -248,14 +248,23 @@ class CodeEditor extends Component {
_render() {
const {compiled} = this.state;
const {containerNodeID} = this.props;
// Until we upgrade Gatsby to React 18, fake the new root API.
const root = {
render: element => {
ReactDOM.render(element, document.getElementById(containerNodeID));
},
};
try {
// Example code requires React, ReactDOM, and Remarkable to be within scope.
// It also requires a "mountNode" variable for ReactDOM.render()
// eslint-disable-next-line no-new-func
new Function('React', 'ReactDOM', 'Remarkable', compiled)(
new Function('React', 'ReactDOM', 'root', 'Remarkable', compiled)(
React,
ReactDOM,
root,
Remarkable,
);
} catch (error) {

9
src/pages/versions.js

@ -40,8 +40,15 @@ const Versions = ({location}: Props) => (
on GitHub
</a>
.<br />
Documentation for recent releases can also be found below.
Changelogs for recent releases can also be found below.
</p>
<blockquote>
<p>Note</p>
<p>
The current docs are for React 18. For React 17, see{' '}
<a href="https://17.reactjs.org">https://17.reactjs.org.</a>
</p>
</blockquote>
<p>
See our FAQ for information about{' '}
<a href="/docs/faq-versioning.html">

2
src/site-constants.js

@ -8,7 +8,7 @@
// NOTE: We can't just use `location.toString()` because when we are rendering
// the SSR part in node.js we won't have a proper location.
const urlRoot = 'https://reactjs.org';
const version = '17.0.2';
const version = '18.0.0';
const babelURL = 'https://unpkg.com/babel-standalone@6.26.0/babel.min.js';
export {babelURL, urlRoot, version};

27
vercel.json

@ -248,6 +248,31 @@
"source": "/version/16.0",
"destination": "https://5a046bf5a6188f4b8fa4938a--reactjs.netlify.com",
"permanent": false
},
{
"source": "/docs/concurrent-mode-adoption.html",
"destination": "https://17.reactjs.org/docs/concurrent-mode-adoption.html",
"permanent": true
},
{
"source": "/docs/concurrent-mode-intro.html",
"destination": "https://17.reactjs.org/docs/concurrent-mode-intro.html",
"permanent": true
},
{
"source": "/docs/concurrent-mode-patterns.html",
"destination": "https://17.reactjs.org/docs/concurrent-mode-patterns.html",
"permanent": true
},
{
"source": "/docs/concurrent-mode-reference.html",
"destination": "https://17.reactjs.org/docs/concurrent-mode-reference.html",
"permanent": true
},
{
"source": "/docs/concurrent-mode-suspense.html",
"destination": "https://17.reactjs.org/docs/concurrent-mode-suspense.html",
"permanent": true
}
]
}
}

Loading…
Cancel
Save