Browse Source
* Add ReactDOM Client APIs * Feedback fixes * TODO and link fixes * Update createRoot.md * Nits * Nits * Update reactdomclient.md * Update hydrateRoot.md * Update hydrateRoot.md * Update createRoot.md * Update hydrateRoot.md * createRoot tweaks * bla * tweaks * tweaks * tweak * bump * Add another troubleshooting error Co-authored-by: dan <dan.abramov@gmail.com>main
Ricky
2 years ago
committed by
GitHub
5 changed files with 717 additions and 0 deletions
@ -0,0 +1,430 @@ |
|||
--- |
|||
title: createRoot |
|||
--- |
|||
|
|||
<Intro> |
|||
|
|||
`createRoot` lets you create a root to display React components inside a browser DOM node. |
|||
|
|||
```js |
|||
const root = createRoot(domNode, options?) |
|||
``` |
|||
|
|||
</Intro> |
|||
|
|||
- [Usage](#usage) |
|||
- [Rendering an app fully built with React](#rendering-an-app-fully-built-with-react) |
|||
- [Rendering a page partially built with React](#rendering-a-page-partially-built-with-react) |
|||
- [Updating a root component](#updating-a-root-component) |
|||
- [Reference](#reference) |
|||
- [`createRoot(domNode, options?)`](#create-root) |
|||
- [`root.render(reactNode)`](#root-render) |
|||
- [`root.unmount()`](#root-unmount) |
|||
- [Troubleshooting](#troubleshooting) |
|||
- [I've created a root, but nothing is displayed](#ive-created-a-root-but-nothing-is-displayed) |
|||
- [I'm getting an error: "Target container is not a DOM element"](#im-getting-an-error-target-container-is-not-a-dom-element) |
|||
- [I'm getting an error: "Functions are not valid as a React child."](#im-getting-an-error-functions-are-not-valid-as-a-react-child) |
|||
- [My server-rendered HTML gets re-created from scratch](#my-server-rendered-html-gets-re-created-from-scratch) |
|||
|
|||
--- |
|||
|
|||
## Usage {/*usage*/} |
|||
|
|||
### Rendering an app fully built with React {/*rendering-an-app-fully-built-with-react*/} |
|||
|
|||
If your app is fully built with React, create a single root for your entire app. |
|||
|
|||
```js [[1, 3, "document.getElementById('root')"], [2, 4, "<App />"]] |
|||
import { createRoot } from 'react-dom/client'; |
|||
|
|||
const root = createRoot(document.getElementById('root')); |
|||
root.render(<App />); |
|||
```` |
|||
|
|||
Usually, you only need to run this code once at startup. It will: |
|||
|
|||
1. Find the <CodeStep step={1}>browser DOM node</CodeStep> defined in your HTML. |
|||
2. Display the <CodeStep step={2}>React component</CodeStep> for your app inside. |
|||
|
|||
<Sandpack> |
|||
|
|||
```html index.html |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head><title>My app</title></head> |
|||
<body> |
|||
<!-- This is the DOM node --> |
|||
<div id="root"></div> |
|||
</body> |
|||
</html> |
|||
``` |
|||
|
|||
```js index.js active |
|||
import { createRoot } from 'react-dom/client'; |
|||
import App from './App.js'; |
|||
import './styles.css'; |
|||
|
|||
const root = createRoot(document.getElementById('root')); |
|||
root.render(<App />); |
|||
``` |
|||
|
|||
```js App.js |
|||
import { useState } from 'react'; |
|||
|
|||
export default function App() { |
|||
return ( |
|||
<> |
|||
<h1>Hello, world!</h1> |
|||
<Counter /> |
|||
</> |
|||
); |
|||
} |
|||
|
|||
function Counter() { |
|||
const [count, setCount] = useState(0); |
|||
return ( |
|||
<button onClick={() => setCount(count + 1)}> |
|||
You clicked me {count} times |
|||
</button> |
|||
); |
|||
} |
|||
``` |
|||
|
|||
</Sandpack> |
|||
|
|||
**If your app is fully built with React, you shouldn't need to create any more roots, or to call [`root.render`](#root-render) again.** |
|||
|
|||
From this point on, React will manage the DOM of your entire app. To add more components, [nest them inside the `App` component.](/learn/importing-and-exporting-components) When you need to update the UI, each of your components can do this by [using state](/apis/usestate). When you need to display extra content like a modal or a tooltip outside the DOM node, [render it with a portal.](/apis/createportal) |
|||
|
|||
<Note> |
|||
|
|||
When your HTML is empty, the user sees a blank page until the app's JavaScript code loads and runs: |
|||
|
|||
```html |
|||
<div id="root"></div> |
|||
``` |
|||
|
|||
This can feel very slow! To solve this, you can generate the initial HTML from your components [on the server or during the build.](/apis/reactdomserver) Then your visitors can read text, see images, and click links before any of the JavaScript code loads. We recommend to [use a framework](/learn/start-a-new-react-project#building-with-a-full-featured-framework) that does this optimization out of the box. Depending on when it runs, this is called *server-side rendering (SSR)* or *static site generation (SSG).* |
|||
|
|||
</Note> |
|||
|
|||
<Gotcha> |
|||
|
|||
**Apps using server rendering or static generation must call [`hydrateRoot`](/apis/hydrateRoot) instead of `createRoot`.** React will then *hydrate* (reuse) the DOM nodes from your HTML instead of destroying and re-creating them. |
|||
|
|||
</Gotcha> |
|||
|
|||
--- |
|||
|
|||
### Rendering a page partially built with React {/*rendering-a-page-partially-built-with-react*/} |
|||
|
|||
If your page [isn't fully built with React](/learn/add-react-to-a-website), you can call `createRoot` multiple times to create a root for each top-level piece of UI managed by React. You can display different content in each root by calling [`root.render`](#root-render). |
|||
|
|||
Here, two different React components are rendered into two DOM nodes defined in the `index.html` file: |
|||
|
|||
<Sandpack> |
|||
|
|||
```html public/index.html |
|||
<nav id="navigation"></nav> |
|||
<main> |
|||
<p>This paragraph is not rendered by React (open index.html to verify).</p> |
|||
<section id="comments"></section> |
|||
</main> |
|||
``` |
|||
|
|||
```js index.js active |
|||
import './styles.css'; |
|||
import { createRoot } from 'react-dom/client'; |
|||
import { Comments, Navigation } from './Components.js'; |
|||
|
|||
const navDomNode = document.getElementById('navigation'); |
|||
const navRoot = createRoot(navDomNode); |
|||
navRoot.render(<Navigation />); |
|||
|
|||
const commentDomNode = document.getElementById('comments'); |
|||
const commentRoot = createRoot(commentDomNode); |
|||
commentRoot.render(<Comments />); |
|||
``` |
|||
|
|||
```js Components.js |
|||
export function Navigation() { |
|||
return ( |
|||
<ul> |
|||
<NavLink href="/">Home</NavLink> |
|||
<NavLink href="/about">About</NavLink> |
|||
</ul> |
|||
); |
|||
} |
|||
|
|||
function NavLink({ href, children }) { |
|||
return ( |
|||
<li> |
|||
<a href={href}>{children}</a> |
|||
</li> |
|||
); |
|||
} |
|||
|
|||
export function Comments() { |
|||
return ( |
|||
<> |
|||
<h2>Comments</h2> |
|||
<Comment text="Hello!" author="Sophie" /> |
|||
<Comment text="How are you?" author="Sunil" /> |
|||
</> |
|||
); |
|||
} |
|||
|
|||
function Comment({ text, author }) { |
|||
return ( |
|||
<p>{text} — <i>{author}</i></p> |
|||
); |
|||
} |
|||
``` |
|||
|
|||
```css |
|||
nav ul { padding: 0; margin: 0; } |
|||
nav ul li { display: inline-block; margin-right: 20px; } |
|||
``` |
|||
|
|||
</Sandpack> |
|||
|
|||
You could also create a new DOM node with [`document.createElement()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement) and add it to the document manually. |
|||
|
|||
```js |
|||
const domNode = document.createElement('div'); |
|||
const root = createRoot(domNode); |
|||
root.render(<Comment />); |
|||
document.body.appendChild(domNode); // You can add it anywhere in the document |
|||
``` |
|||
|
|||
To remove the React tree from the DOM node and clean up all the resources used by it, call [`root.unmount`](#root-unmount). |
|||
|
|||
```js |
|||
root.unmount(); |
|||
``` |
|||
|
|||
This is mostly useful if your React components are inside an app written in a different framework. |
|||
|
|||
--- |
|||
|
|||
### Updating a root component {/*updating-a-root-component*/} |
|||
|
|||
You can call `render` more than once on the same root. As long as the component tree structure matches up with what was previously rendered, React will [preserve the state](/learn/preserving-and-resetting-state). Notice how you can type in the input, which means that the updates from repeated `render` calls every second in this example are not destructive: |
|||
|
|||
<Sandpack> |
|||
|
|||
```js index.js active |
|||
import { createRoot } from 'react-dom/client'; |
|||
import './styles.css'; |
|||
import App from './App.js'; |
|||
|
|||
const root = createRoot(document.getElementById('root')); |
|||
|
|||
let i = 0; |
|||
setInterval(() => { |
|||
root.render(<App counter={i} />); |
|||
i++; |
|||
}, 1000); |
|||
``` |
|||
|
|||
```js App.js |
|||
export default function App({counter}) { |
|||
return ( |
|||
<> |
|||
<h1>Hello, world! {counter}</h1> |
|||
<input placeholder="Type something here" /> |
|||
</> |
|||
); |
|||
} |
|||
``` |
|||
|
|||
</Sandpack> |
|||
|
|||
It is uncommon to call `render` multiple times. Usually, you'll [update state](/apis/usestate) inside one of the components instead. |
|||
|
|||
--- |
|||
## Reference {/*reference*/} |
|||
|
|||
### `createRoot(domNode, options?)` {/*create-root*/} |
|||
|
|||
Call `createRoot` to create a React root for displaying content inside a browser DOM element. |
|||
|
|||
```js |
|||
const domNode = document.getElementById('root'); |
|||
const root = createRoot(domNode); |
|||
``` |
|||
|
|||
React will create a root for the `domNode`, and take over managing the DOM inside it. After you've created a root, you need to call [`root.render`](#root-render) to display a React component inside of it: |
|||
|
|||
```js |
|||
root.render(<App />); |
|||
``` |
|||
|
|||
An app fully built with React will usually only have one `createRoot` call for its root component. A page that uses "sprinkles" of React for parts of the page may have as many separate roots as needed. |
|||
|
|||
[See examples above.](#usage) |
|||
|
|||
#### Parameters {/*parameters*/} |
|||
|
|||
|
|||
* `domNode`: A [DOM element](https://developer.mozilla.org/en-US/docs/Web/API/Element). React will create a root for this DOM element and allow you to call functions on the root, such as `render` to display rendered React content. |
|||
|
|||
* **optional** `options`: A object contain options for this React root. |
|||
|
|||
* `onRecoverableError`: optional callback called when React automatically recovers from errors. |
|||
* `identifierPrefix`: optional prefix React uses for IDs generated by [`useId`](/apis/useid). Useful to avoid conflicts when using multiple roots on the same page. |
|||
#### Returns {/*returns*/} |
|||
|
|||
`createRoot` returns an object with two methods: [`render`](#root-render) and [`unmount`](#root-unmount). |
|||
|
|||
#### Caveats {/*caveats*/} |
|||
* If your app is server-rendered, using `createRoot()` is not supported. Use [`hydrateRoot()`](/apis/react-dom/client/hydrateRoot) instead. |
|||
* You'll likely have only one `createRoot` call in your app. If you use a framework, it might do this call for you. |
|||
* When you want to render a piece of JSX in a different part of the DOM tree that isn't a child of your component (for example, a modal or a tooltip), use [`createPortal`](/apis/react-dom/createPortal) instead of `createRoot`. |
|||
|
|||
--- |
|||
|
|||
### `root.render(reactNode)` {/*root-render*/} |
|||
|
|||
Call `root.render` to display a piece of [JSX](/learn/writing-markup-with-jsx) ("React node") into the React root's browser DOM node. |
|||
|
|||
```js |
|||
root.render(<App />); |
|||
``` |
|||
|
|||
React will display `<App />` in the `root`, and take over managing the DOM inside it. |
|||
|
|||
[See examples above.](#usage) |
|||
|
|||
#### Parameters {/*parameters*/} |
|||
|
|||
* `reactNode`: A *React node* that you want to display. This will usually be a piece of JSX like `<App />`, but you can also pass a React element constructed with [`createElement()`](/apis/react/createElement), a string, a number, `null`, or `undefined`. |
|||
|
|||
|
|||
#### Returns {/*returns*/} |
|||
|
|||
`root.render` returns `undefined`. |
|||
|
|||
#### Caveats {/*caveats*/} |
|||
|
|||
* The first time you call `root.render`, React will clear all the existing HTML content inside the React root before rendering the React component into it. |
|||
|
|||
* If your root's DOM node contains HTML generated by React on the server or during the build, use [`hydrateRoot()`](/apis/react-dom/client/hydrateRoot) instead, which attaches the event handlers to the existing HTML. |
|||
|
|||
* If you call `render` on the same root more than once, React will update the DOM as necessary to reflect the latest JSX you passed. React will decide which parts of the DOM can be reused and which need to be recreated by ["matching it up"](/learn/preserving-and-resetting-state) with the previously rendered tree. Calling `render` on the same root again is similar to calling the [`set` function](/apis/usestate#setstate) on the root component: React avoids unnecessary DOM updates. |
|||
|
|||
--- |
|||
|
|||
### `root.unmount()` {/*root-unmount*/} |
|||
|
|||
Call `root.unmount` to destroy a rendered tree inside a React root. |
|||
|
|||
```js |
|||
root.unmount(); |
|||
``` |
|||
|
|||
An app fully built with React will usually not have any calls to `root.unmount`. |
|||
|
|||
This is mostly useful if your React root's DOM node (or any of its ancestors) may get removed from the DOM by some other code. For example, imagine a jQuery tab panel that removes inactive tabs from the DOM. If a tab gets removed, everything inside it (including the React roots inside) would get removed from the DOM as well. In that case, you need to tell React to "stop" managing the removed root's content by calling `root.unmount`. Otherwise, the components inside the removed root won't know to clean up and free up global resources like subscriptions. |
|||
|
|||
Calling `root.unmount` will unmount all the components in the root and "detach" React from the root DOM node, including removing any event handlers or state in the tree. |
|||
|
|||
|
|||
#### Parameters {/*parameters*/} |
|||
|
|||
`root.unmount` does not accept any parameters. |
|||
|
|||
|
|||
#### Returns {/*returns*/} |
|||
|
|||
`root.unmount` returns `undefined`. |
|||
|
|||
#### Caveats {/*caveats*/} |
|||
|
|||
* Calling `root.unmount` will unmount all the components in the tree and "detach" React from the root DOM node. |
|||
|
|||
* Once you call `root.unmount` you cannot call `root.render` again on the same root. Attempting to call `root.render` on an unmounted root will throw a "Cannot update an unmounted root" error. However, you can create a new root for the same DOM node after the previous root for that node has been unmounted. |
|||
|
|||
--- |
|||
|
|||
## Troubleshooting {/*troubleshooting*/} |
|||
|
|||
### I've created a root, but nothing is displayed {/*ive-created-a-root-but-nothing-is-displayed*/} |
|||
|
|||
Make sure you haven't forgotten to actually *render* your app into the root: |
|||
|
|||
```js {5} |
|||
import { createRoot } from 'react-dom/client'; |
|||
import App from './App.js'; |
|||
|
|||
const root = createRoot(document.getElementById('root')); |
|||
root.render(<App />); |
|||
```` |
|||
|
|||
Until you do that, nothing is displayed. |
|||
|
|||
### I'm getting an error: "Target container is not a DOM element" {/*im-getting-an-error-target-container-is-not-a-dom-element*/} |
|||
|
|||
This error means that whatever you're passing to `createRoot` is not a DOM node. |
|||
|
|||
If you're not sure what's happening, try logging it: |
|||
|
|||
```js {2} |
|||
const domNode = document.getElementById('root'); |
|||
console.log(domNode); // ??? |
|||
const root = createRoot(domNode); |
|||
root.render(<App />); |
|||
```` |
|||
|
|||
For example, if `domNode` is `null`, it means that [`getElementById`](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById) returned `null`. This will happen if there is no node in the document with the given ID at the time of your call. There may be a few reasons for it: |
|||
|
|||
1. The ID you're looking for might differ from the ID you used in the HTML file. Check for typos! |
|||
2. Your bundle's `<script>` tag cannot "see" any DOM nodes that appear *after* it in the HTML. |
|||
|
|||
If you can't get it working, check out [Adding React to a Website](/learn/add-react-to-a-website) for a working example. |
|||
|
|||
Another common way to get this error is to write `createRoot(<App />)` instead of `createRoot(domNode)`. |
|||
|
|||
### I'm getting an error: "Functions are not valid as a React child." {/*im-getting-an-error-functions-are-not-valid-as-a-react-child*/} |
|||
|
|||
This error means that whatever you're passing to `root.render` is not a React component. |
|||
|
|||
This may happen if you call `root.render` with `Component` instead of `<Component />`: |
|||
|
|||
```js {2,5} |
|||
// 🚩 Wrong: App is a function, not a Component. |
|||
root.render(App); |
|||
|
|||
// ✅ Correct: <App /> is a component. |
|||
root.render(<App />); |
|||
```` |
|||
|
|||
Or if you pass a function to `root.render`, instead of the result of calling it: |
|||
|
|||
```js {2,5} |
|||
// 🚩 Wrong: createApp is a function, not a component. |
|||
root.render(createApp); |
|||
|
|||
// ✅ Correct: call createApp to return a component. |
|||
root.render(createApp()); |
|||
``` |
|||
|
|||
If you can't get it working, check out [Adding React to a Website](/learn/add-react-to-a-website) for a working example. |
|||
|
|||
### My server-rendered HTML gets re-created from scratch {/*my-server-rendered-html-gets-re-created-from-scratch*/} |
|||
|
|||
If your app is server-rendered and includes the initial HTML generated by React, you might notice that creating a root and calling `root.render` deletes all that HTML, and then re-creates all the DOM nodes from scratch. This can be slower, resets focus and scroll positions, and may lose other user input. |
|||
|
|||
Server-rendered apps must use [`hydrateRoot`](/apis/hydrateRoot) instead of `createRoot`: |
|||
|
|||
```js {1,4-7} |
|||
import { hydrateRoot } from 'react-dom/client'; |
|||
import App from './App.js'; |
|||
|
|||
hydrateRoot( |
|||
document.getElementById('root'), |
|||
<App /> |
|||
); |
|||
``` |
|||
|
|||
Note that its API is different. In particular, usually there will be no further `root.render` call. |
@ -0,0 +1,248 @@ |
|||
--- |
|||
title: hydrateRoot |
|||
--- |
|||
|
|||
<Intro> |
|||
|
|||
`hydrateRoot` lets you display React components inside a browser DOM node whose HTML content was previously generated by [`react-dom/server`](/apis/reactdomserver). |
|||
|
|||
```js |
|||
const root = hydrateRoot(domNode, reactNode, options?) |
|||
``` |
|||
|
|||
</Intro> |
|||
|
|||
- [Usage](#usage) |
|||
- [Hydrating server-rendered HTML](#hydrating-server-rendered-html) |
|||
- [Updating a hydrated root component](#updating-a-hydrated-root-component) |
|||
- [Reference](#reference) |
|||
- [`hydrateRoot(domNode, reactNode, options?)`](#hydrate-root) |
|||
- [`root.render(reactNode)`](#root-render) |
|||
- [`root.unmount()`](#root-unmount) |
|||
|
|||
--- |
|||
|
|||
## Usage {/*usage*/} |
|||
|
|||
### Hydrating server-rendered HTML {/*hydrating-server-rendered-html*/} |
|||
|
|||
If your app's HTML was generated by [`react-dom/server`](/apis/createRoot), you need to *hydrate* it on the client. |
|||
|
|||
```js [[1, 3, "document.getElementById('root')"], [2, 3, "<App />"]] |
|||
import {hydrateRoot} from 'react-dom/client'; |
|||
|
|||
hydrateRoot(document.getElementById('root'), <App />); |
|||
```` |
|||
|
|||
This will hydrate the server HTML inside the <CodeStep step={1}>browser DOM node</CodeStep> with the <CodeStep step={2}>React component</CodeStep> for your app. Usually, you will do it once at startup. If you use a framework, it might do this behind the scenes for you. |
|||
|
|||
To hydrate your app, React will "attach" your components' logic to the initial generated HTML from the server. Hydration turns the initial HTML snapshot from the server into a fully interactive app that runs in the browser. |
|||
|
|||
<Sandpack> |
|||
|
|||
```html public/index.html |
|||
<!-- |
|||
HTML content inside <div id="root">...</div> |
|||
was generated from App by react-dom/server. |
|||
--> |
|||
<div id="root"><h1>Hello, world!</h1><button>You clicked me <!-- -->0<!-- --> times</button></div> |
|||
``` |
|||
|
|||
```js index.js active |
|||
import './styles.css'; |
|||
import {hydrateRoot} from 'react-dom/client'; |
|||
import App from './App.js'; |
|||
|
|||
hydrateRoot( |
|||
document.getElementById('root'), |
|||
<App /> |
|||
); |
|||
``` |
|||
|
|||
```js App.js |
|||
import { useState } from 'react'; |
|||
|
|||
export default function App() { |
|||
return ( |
|||
<> |
|||
<h1>Hello, world!</h1> |
|||
<Counter /> |
|||
</> |
|||
); |
|||
} |
|||
|
|||
function Counter() { |
|||
const [count, setCount] = useState(0); |
|||
return ( |
|||
<button onClick={() => setCount(count + 1)}> |
|||
You clicked me {count} times |
|||
</button> |
|||
); |
|||
} |
|||
``` |
|||
|
|||
</Sandpack> |
|||
|
|||
You shouldn't need to call `hydrateRoot` again or to call it in more places. From this point on, React will be managing the DOM of your application. If you want to update the UI, your components can do this by [using state](/apis/usestate). |
|||
|
|||
<Gotcha> |
|||
|
|||
The React tree you pass to `hydrateRoot` needs to produce **the same output** as it did on the server. |
|||
|
|||
This is important for the user experience. The user will spend some time looking at the server-generated HTML before your JavaScript code loads. Server rendering creates an illusion that the app loads faster by showing the HTML snapshot of its output. Suddenly showing different content breaks that illusion. This is why the server render output must match the initial render output on the client during hydration. |
|||
|
|||
The most common causes leading to hydration errors include: |
|||
|
|||
* Extra whitespace (like newlines) around the React-generated HTML inside the root node. |
|||
* Using checks like `typeof window !== 'undefined'` in your rendering logic. |
|||
* Using browser-only APIs like [`window.matchMedia`](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia) in your rendering logic. |
|||
* Rendering different data on the server and the client. |
|||
|
|||
React can recover from some hydration errors, but **you must fix them like other bugs.** In the best case, they'll lead to a slower app; in the worst case, event handlers would get attached to the wrong elements. |
|||
|
|||
</Gotcha> |
|||
|
|||
### Updating a hydrated root component {/*updating-a-hydrated-root-component*/} |
|||
|
|||
After the root has finished hydrating, you can call [`root.render`](#root-render) to update the root React component. **Unlike with [`createRoot`](/apis/createRoot), you don't usually need to do this because the initial content was already rendered as HTML.** |
|||
|
|||
If you call `root.render` at some point after hydration, and the component tree structure matches up with what was previously rendered, React will [preserve the state](/learn/preserving-and-resetting-state). Notice how you can type in the input, which means that the updates from repeated `render` calls every second in this example are not destructive: |
|||
|
|||
<Sandpack> |
|||
|
|||
```html public/index.html |
|||
<!-- |
|||
All HTML content inside <div id="root">...</div> was |
|||
generated by rendering <App /> with react-dom/server. |
|||
--> |
|||
<div id="root"><h1>Hello, world! <!-- -->0</h1><input placeholder="Type something here"/></div> |
|||
``` |
|||
|
|||
```js index.js active |
|||
import {hydrateRoot} from 'react-dom/client'; |
|||
import './styles.css'; |
|||
import App from './App.js'; |
|||
|
|||
const root = hydrateRoot( |
|||
document.getElementById('root'), |
|||
<App counter={0} /> |
|||
); |
|||
|
|||
let i = 0; |
|||
setInterval(() => { |
|||
root.render(<App counter={i} />); |
|||
i++; |
|||
}, 1000); |
|||
``` |
|||
|
|||
```js App.js |
|||
export default function App({counter}) { |
|||
return ( |
|||
<> |
|||
<h1>Hello, world! {counter}</h1> |
|||
<input placeholder="Type something here" /> |
|||
</> |
|||
); |
|||
} |
|||
``` |
|||
|
|||
</Sandpack> |
|||
|
|||
It is uncommon to call [`root.render`](#root-render) on a hydrated root. Usually, you'll [update state](/apis/usestate) inside one of the components instead. |
|||
|
|||
|
|||
--- |
|||
## Reference {/*reference*/} |
|||
|
|||
### `hydrateRoot(domNode, options?)` {/*hydrate-root*/} |
|||
|
|||
Call `hydrateRoot` to “attach” React to existing HTML that was already rendered by React in a server environment. |
|||
|
|||
```js |
|||
const domNode = document.getElementById('root'); |
|||
const root = hydrateRoot(domNode, reactNode); |
|||
``` |
|||
|
|||
React will attach to the HTML that exists inside the `domNode`, and take over managing the DOM inside it. An app fully built with React will usually only have one `hydrateRoot` call with its root component. |
|||
|
|||
[See examples above.](#usage) |
|||
|
|||
#### Parameters {/*parameters*/} |
|||
|
|||
* `domNode`: A [DOM element](https://developer.mozilla.org/en-US/docs/Web/API/Element) that was rendered as the root element on the server. |
|||
|
|||
* `reactNode`: The "React node" used to render the existing HTML. This will usually be a piece of JSX like `<App />` which was rendered with a `ReactDOM Server` method such as `renderToPipeableStream(<App />)`. |
|||
|
|||
* **optional** `options`: A object contain options for this React root. |
|||
|
|||
* `onRecoverableError`: optional callback called when React automatically recovers from errors. |
|||
* `identifierPrefix`: optional prefix React uses for IDs generated by [`useId`](/apis/useid). Useful to avoid conflicts when using multiple roots on the same page. Must be the same prefix as used on the server. |
|||
|
|||
#### Returns {/*returns*/} |
|||
|
|||
`hydrateRoot` returns an object with two methods: [`render`](#root-render) and [`unmount`](#root-unmount). |
|||
|
|||
#### Caveats {/*caveats*/} |
|||
* `hydrateRoot()` expects the rendered content to be identical with the server-rendered content. 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. |
|||
* You'll likely have only one `hydrateRoot` call in your app. If you use a framework, it might do this call for you. |
|||
* If your app is client-rendered with no HTML rendered already, using `hydrateRoot()` is not supported. Use [`createRoot()`](/apis/createRoot) instead. |
|||
|
|||
--- |
|||
|
|||
### `root.render(reactNode)` {/*root-render*/} |
|||
|
|||
Call `root.render` to update a React component inside a hydrated React root for a browser DOM element. |
|||
|
|||
```js |
|||
root.render(<App />); |
|||
``` |
|||
|
|||
React will update `<App />` in the hydrated `root`. |
|||
|
|||
[See examples above.](#usage) |
|||
|
|||
#### Parameters {/*parameters*/} |
|||
|
|||
* `reactNode`: A "React node" that you want to update. This will usually be a piece of JSX like `<App />`, but you can also pass a React element constructed with [`createElement()`](/apis/react/createElement), a string, a number, `null`, or `undefined`. |
|||
|
|||
|
|||
#### Returns {/*returns*/} |
|||
|
|||
`root.render` returns `undefined`. |
|||
|
|||
#### Caveats {/*caveats*/} |
|||
|
|||
* If you call `root.render` before the root has finished hydrating, React will clear the existing server-rendered HTML content and switch the entire root to client rendering. |
|||
|
|||
--- |
|||
|
|||
### `root.unmount()` {/*root-unmount*/} |
|||
|
|||
Call `root.unmount` to destroy a rendered tree inside a React root. |
|||
|
|||
```js |
|||
root.unmount(); |
|||
``` |
|||
|
|||
An app fully built with React will usually not have any calls to `root.unmount`. |
|||
|
|||
This is mostly useful if your React root's DOM node (or any of its ancestors) may get removed from the DOM by some other code. For example, imagine a jQuery tab panel that removes inactive tabs from the DOM. If a tab gets removed, everything inside it (including the React roots inside) would get removed from the DOM as well. In that case, you need to tell React to "stop" managing the removed root's content by calling `root.unmount`. Otherwise, the components inside the removed root won't know to clean up and free up global resources like subscriptions. |
|||
|
|||
Calling `root.unmount` will unmount all the components in the root and "detach" React from the root DOM node, including removing any event handlers or state in the tree. |
|||
|
|||
|
|||
#### Parameters {/*parameters*/} |
|||
|
|||
`root.unmount` does not accept any parameters. |
|||
|
|||
|
|||
#### Returns {/*returns*/} |
|||
|
|||
`render` returns `null`. |
|||
|
|||
#### Caveats {/*caveats*/} |
|||
|
|||
* Calling `root.unmount` will unmount all the components in the tree and "detach" React from the root DOM node. |
|||
|
|||
* Once you call `root.unmount` you cannot call `root.render` again on the root. Attempting to call `root.render` on an unmounted root will throw a "Cannot update an unmounted root" error. |
@ -0,0 +1,14 @@ |
|||
--- |
|||
title: ReactDOM Client APIs |
|||
--- |
|||
|
|||
<Intro> |
|||
|
|||
The ReactDOM client APIs let you render a React application in the browser. |
|||
|
|||
</Intro> |
|||
|
|||
Typically, you will use these APIs at the top level of your app to display your components. You will either use them directly or a [framework](/learn/start-a-new-react-project#building-with-react-and-a-framework) may do it for you. Most of your components should *not* need to import these APIs. |
|||
|
|||
|
|||
Note: This section is incomplete and is still being written! |
Loading…
Reference in new issue