[Try it on CodePen.](http://codepen.io/gaearon/pen/ozqNOV?editors=0010)
[Try it on CodePen.](https://codepen.io/gaearon/pen/ozqNOV?editors=0010)
Anything inside the `<FancyBorder>` JSX tag gets passed into the `FancyBorder` component as a `children` prop. Since `FancyBorder` renders `{props.children}` inside a `<div>`, the passed elements appear in the final output.
Anything inside the `<FancyBorder>` JSX tag gets passed into the `FancyBorder` component as a `children` prop. Since `FancyBorder` renders `{props.children}` inside a `<div>`, the passed elements appear in the final output.
@ -77,7 +77,7 @@ function App() {
}
}
```
```
[Try it on CodePen.](http://codepen.io/gaearon/pen/gwZOJp?editors=0010)
[Try it on CodePen.](https://codepen.io/gaearon/pen/gwZOJp?editors=0010)
React elements like `<Contacts />` and `<Chat />` are just objects, so you can pass them as props like any other data.
React elements like `<Contacts />` and `<Chat />` are just objects, so you can pass them as props like any other data.
@ -110,7 +110,7 @@ function WelcomeDialog() {
}
}
```
```
[Try it on CodePen.](http://codepen.io/gaearon/pen/kkEaOZ?editors=0010)
[Try it on CodePen.](https://codepen.io/gaearon/pen/kkEaOZ?editors=0010)
Composition works equally well for components defined as classes:
Composition works equally well for components defined as classes:
@ -160,7 +160,7 @@ class SignUpDialog extends React.Component {
}
}
```
```
[Try it on CodePen.](http://codepen.io/gaearon/pen/gwZbYa?editors=0010)
[Try it on CodePen.](https://codepen.io/gaearon/pen/gwZbYa?editors=0010)
@ -56,7 +56,7 @@ class Calculator extends React.Component {
}
}
```
```
[Try it on CodePen.](http://codepen.io/valscion/pen/VpZJRZ?editors=0010)
[Try it on CodePen.](https://codepen.io/gaearon/pen/ZXeOBm?editors=0010)
## Adding a Second Input
## Adding a Second Input
@ -110,7 +110,7 @@ class Calculator extends React.Component {
}
}
```
```
[Try it on CodePen.](http://codepen.io/valscion/pen/GWKbao?editors=0010)
[Try it on CodePen.](https://codepen.io/gaearon/pen/jGBryx?editors=0010)
We have two inputs now, but when you enter the temperature in one of them, the other doesn't update. This contradicts our requirement: we want to keep them in sync.
We have two inputs now, but when you enter the temperature in one of them, the other doesn't update. This contradicts our requirement: we want to keep them in sync.
@ -296,7 +296,7 @@ class Calculator extends React.Component {
}
}
```
```
[Try it on CodePen.](http://codepen.io/valscion/pen/jBNjja?editors=0010)
[Try it on CodePen.](https://codepen.io/gaearon/pen/WZpxpz?editors=0010)
Now, no matter which input you edit, `this.state.temperature` and `this.state.scale` in the `Calculator` get updated. One of the inputs gets the value as is, so any user input is preserved, and the other input value is always recalculated based on it.
Now, no matter which input you edit, `this.state.temperature` and `this.state.scale` in the `Calculator` get updated. One of the inputs gets the value as is, so any user input is preserved, and the other input value is always recalculated based on it.
@ -77,8 +100,9 @@ class Parent extends React.Component {
}
}
handleClick() {
handleClick() {
// This will fire when the button in Child is clicked, updating Parent's state,
// This will fire when the button in Child is clicked,
// even though Child is not a direct descendant in the DOM.
// updating Parent's state, even though button
// is not direct descendant in the DOM.
this.setState(prevState => ({
this.setState(prevState => ({
clicks: prevState.clicks + 1
clicks: prevState.clicks + 1
}));
}));
@ -86,10 +110,17 @@ class Parent extends React.Component {
render() {
render() {
return (
return (
<divonClick={this.onClick}>
<divonClick={this.handleClick}>
<p>Number of clicks: {this.state.clicks}</p>
<p>Number of clicks: {this.state.clicks}</p>
<p>Open up the browser DevTools to observe that the button is not a child the div with onClick handler.</p>
<p>
{ReactDOM.createPortal(<Child/>, modalRoot)}
Open up the browser DevTools
to observe that the button
is not a child the div
with onClick handler.
</p>
<Modal>
<Child/>
</Modal>
</div>
</div>
);
);
}
}
@ -105,10 +136,9 @@ function Child() {
);
);
}
}
ReactDOM.render(<Parent/>, appRoot);
ReactDOM.render(<Parent/>, appRoot);
```
```
[Try this example on CodePen](https://codepen.io/gaearon/pen/jGBWpE).
[Try it on CodePen.](https://codepen.io/gaearon/pen/jGBWpE).
Catching an event bubbling up from a portal in a parent component allows the development of more flexible abstractions that are not inherently reliant on portals. For example, if you render a `<Modal />` component, the parent can capture its events regardless of whether it's implemented using portals.
Catching an event bubbling up from a portal in a parent component allows the development of more flexible abstractions that are not inherently reliant on portals. For example, if you render a `<Modal />` component, the parent can capture its events regardless of whether it's implemented using portals.
@ -98,7 +98,19 @@ The `value` attribute is supported by `<input>` and `<textarea>` components. You
## All Supported HTML Attributes
## All Supported HTML Attributes
React supports all `data-*` and `aria-*` attributes as well as these attributes:
As of React 16, any standard [or custom](/react/blog/2017/09/08/dom-attributes-in-react-16.html) DOM attributes are fully supported.
React has always provided a JavaScript-centric API to the DOM. Since React components often take both custom and DOM-related props, React uses the `camelCase` convention just like the DOM APIs:
```js
<divtabIndex="-1"/> // Just like node.tabIndex DOM API
<divclassName="Button"/> // Just like node.className DOM API
<inputreadOnly={true}/> // Just like node.readOnly DOM API
```
These props work similarly to the corresponding HTML attributes, with the exception of the special cases documented above.
Some of the DOM attributes supported by React include:
```
```
accept acceptCharset accessKey action allowFullScreen allowTransparency alt
accept acceptCharset accessKey action allowFullScreen allowTransparency alt
@ -61,7 +61,7 @@ Now that we've identified the components in our mock, let's arrange them into a
## Step 2: Build A Static Version in React
## Step 2: Build A Static Version in React
<pdata-height="600"data-theme-id="0"data-slug-hash="vXpAgj"data-default-tab="js"data-user="lacker"data-embed-version="2"class="codepen">See the Pen <ahref="http://codepen.io/lacker/pen/vXpAgj/">Thinking In React: Step 2</a> on <ahref="http://codepen.io">CodePen</a>.</p>
<pdata-height="600"data-theme-id="0"data-slug-hash="BwWzwm"data-default-tab="js"data-user="lacker"data-embed-version="2"class="codepen">See the Pen <ahref="https://codepen.io/gaearon/pen/BwWzwm">Thinking In React: Step 2</a> on <ahref="http://codepen.io">CodePen</a>.</p>
Now that you have your component hierarchy, it's time to implement your app. The easiest way is to build a version that takes your data model and renders the UI but has no interactivity. It's best to decouple these processes because building a static version requires a lot of typing and no thinking, and adding interactivity requires a lot of thinking and not a lot of typing. We'll see why.
Now that you have your component hierarchy, it's time to implement your app. The easiest way is to build a version that takes your data model and renders the UI but has no interactivity. It's best to decouple these processes because building a static version requires a lot of typing and no thinking, and adding interactivity requires a lot of thinking and not a lot of typing. We'll see why.
@ -106,7 +106,7 @@ So finally, our state is:
## Step 4: Identify Where Your State Should Live
## Step 4: Identify Where Your State Should Live
<pdata-height="600"data-theme-id="0"data-slug-hash="ORzEkG"data-default-tab="js"data-user="lacker"data-embed-version="2"class="codepen">See the Pen <ahref="http://codepen.io/lacker/pen/ORzEkG/">Thinking In React: Step 4</a> by Kevin Lacker (<ahref="http://codepen.io/lacker">@lacker</a>) on <ahref="http://codepen.io">CodePen</a>.</p>
<pdata-height="600"data-theme-id="0"data-slug-hash="qPrNQZ"data-default-tab="js"data-user="lacker"data-embed-version="2"class="codepen">See the Pen <ahref="https://codepen.io/gaearon/pen/qPrNQZ">Thinking In React: Step 4</a> on <ahref="http://codepen.io">CodePen</a>.</p>
OK, so we've identified what the minimal set of app state is. Next, we need to identify which component mutates, or *owns*, this state.
OK, so we've identified what the minimal set of app state is. Next, we need to identify which component mutates, or *owns*, this state.
@ -132,7 +132,7 @@ You can start seeing how your application will behave: set `filterText` to `"bal
## Step 5: Add Inverse Data Flow
## Step 5: Add Inverse Data Flow
<pdata-height="600"data-theme-id="0"data-slug-hash="qRqmjd"data-default-tab="js,result"data-user="rohan10"data-embed-version="2"data-pen-title="Thinking In React: Step 5"class="codepen">See the Pen <ahref="http://codepen.io/rohan10/pen/qRqmjd">Thinking In React: Step 5</a> on <ahref="http://codepen.io">CodePen</a>.</p>
<pdata-height="600"data-theme-id="0"data-slug-hash="LzWZvb"data-default-tab="js,result"data-user="rohan10"data-embed-version="2"data-pen-title="Thinking In React: Step 5"class="codepen">See the Pen <ahref="https://codepen.io/gaearon/pen/LzWZvb">Thinking In React: Step 5</a> on <ahref="http://codepen.io">CodePen</a>.</p>
So far, we've built an app that renders correctly as a function of props and state flowing down the hierarchy. Now it's time to support data flowing the other way: the form components deep in the hierarchy need to update the state in `FilterableProductTable`.
So far, we've built an app that renders correctly as a function of props and state flowing down the hierarchy. Now it's time to support data flowing the other way: the form components deep in the hierarchy need to update the state in `FilterableProductTable`.