Skip to content

Commit

Permalink
[18] Switch code samples to createRoot (#4470)
Browse files Browse the repository at this point in the history
* [18] Switch code samples to createRoot

* Feedback fixes

* Feedback updates
  • Loading branch information
rickhanlonii committed Mar 29, 2022
1 parent 2610a05 commit 4af46e5
Show file tree
Hide file tree
Showing 27 changed files with 108 additions and 188 deletions.
19 changes: 10 additions & 9 deletions beta/src/pages/learn/add-react-to-a-website.md
Original file line number Diff line number Diff line change
Expand Up @@ -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!**
Expand All @@ -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)!
Expand Down Expand Up @@ -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>
```

Expand Down
7 changes: 4 additions & 3 deletions content/docs/add-react-to-a-website.md
Original file line number Diff line number Diff line change
Expand Up @@ -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}

Expand Down
2 changes: 1 addition & 1 deletion content/docs/addons-shallow-renderer.md
Original file line number Diff line number Diff line change
Expand Up @@ -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}

Expand Down
6 changes: 3 additions & 3 deletions content/docs/addons-test-utils.md
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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');
Expand Down Expand Up @@ -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:
Expand Down
13 changes: 3 additions & 10 deletions content/docs/components-and-props.md
Original file line number Diff line number Diff line change
Expand Up @@ -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>`.
Expand Down Expand Up @@ -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)**
Expand Down
2 changes: 1 addition & 1 deletion content/docs/concurrent-mode-adoption.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ import ReactDOM from 'react-dom';
//
// You can opt into Concurrent Mode by writing:

ReactDOM.unstable_createRoot(
ReactDOM.createRoot(
document.getElementById('root')
).render(<App />);
```
Expand Down
4 changes: 2 additions & 2 deletions content/docs/forms.md
Original file line number Diff line number Diff line change
Expand Up @@ -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);

```
Expand Down
5 changes: 0 additions & 5 deletions content/docs/handling-events.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
9 changes: 4 additions & 5 deletions content/docs/hello-world.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions content/docs/hooks-faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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');
Expand Down
11 changes: 6 additions & 5 deletions content/docs/implementation-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 />);
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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) {
Expand Down
40 changes: 14 additions & 26 deletions content/docs/integrating-with-other-libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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:
Expand All @@ -240,44 +234,40 @@ 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>;
}
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);
}
});
```

[**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.

Expand Down Expand Up @@ -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)
Expand Down
10 changes: 0 additions & 10 deletions content/docs/introducing-jsx.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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)**
Expand Down
Loading

0 comments on commit 4af46e5

Please sign in to comment.