React
React
React
MAIN CONCEPTS
1. Hello World
2. Introducing JSX
3. Rendering Elements
4. Components and Props
5. State and Lifecycle
6. Handling Events
7. Conditional Rendering
8. Lists and Keys
9. Forms
10. Lifting State Up
11. Composition vs Inheritance
12. Thinking In React
1. Hello World
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
Why JSX?
ReactDOM.render(
element,
document.getElementById('root')
);
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
ReactDOM.render(
element,
document.getElementById('root')
);
// Hello, Harper Perez!
Warning:
Since JSX is closer to JavaScript than to HTML, React DOM
uses camelCase property naming convention instead of HTML
attribute names.
For example, class becomes className in JSX,
and tabindex becomes tabIndex.
const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
);
3. Rendering Elements
Note:
One might confuse elements with a more widely known concept
of “components”. We will introduce components in the next
section. Elements are what components are “made of”, and we
encourage you to read this section before jumping ahead.
<div id=“root"></div>
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new
Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(element,
document.getElementById('root'));
}
setInterval(tick, 1000);
Note:
In practice, most React apps only
call ReactDOM.render() once.
In the next sections we will learn how such code gets
encapsulated into stateful components.
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
This function is a valid React component because it accepts a
single “props” (which stands for properties) object argument
with data and returns a React element. We call such
components “functional” because they are literally JavaScript
functions.
Rendering a Component
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Typically, new React apps have a single App component at the
very top. However, if you integrate React into an existing app,
you might start bottom-up with a small component
like Button and gradually work your way to the top of the view
hierarchy.
Extracting Components
function Avatar(props) {
return (
<img className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name}
/>
);
}
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<Avatar user={props.author} />
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
function sum(a, b) {
return a + b;
}
Such functions are called “pure” because they do not attempt to
change their inputs, and always return the same result for the
same inputs.
setInterval(tick, 1000);
Try it on CodePen
In this section, we will learn how to make the Clock component
truly reusable and encapsulated. It will set up its own timer and
update itself every second.
We can start by encapsulating how the clock looks:
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}
setInterval(tick, 1000);
Try it on CodePen
However, it misses a crucial requirement: the fact that
the Clock sets up a timer and updates the UI every second
should be an implementation detail of the Clock.
Ideally we want to write this once and have the Clock update
itself:
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
To implement this, we need to add “state” to
the Clock component.
State is similar to props, but it is private and fully controlled by
the component.
We mentioned before that components defined as classes have
some additional features. Local state is exactly that: a feature
available only to classes.
Converting a Function to a Class
You can convert a functional component like Clock to a class in
five steps:
1. Create an ES6 class, with the same name, that
extends React.Component.
4. Replace props with this.props in the render() body.
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is
{this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
Note how we pass props to the base constructor:
constructor(props) {
super(props);
this.state = {date: new Date()};
}
Class components should always call the base constructor
with props.
3. Remove the date prop from the <Clock /> element:
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
We will later add the timer code back to the component itself.
The result looks like this:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is
{this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
Try it on CodePen
Next, we’ll make the Clock set up its own timer and update
itself every second.
componentDidMount() {
componentWillUnmount() {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is
{this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
These methods are called “lifecycle hooks”.
The componentDidMount() hook runs after the component
output has been rendered to the DOM. This is a good place to
set up a timer:
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
Note how we save the timer ID right on this.
While this.props is set up by React itself
and this.state has a special meaning, you are free to add
additional fields to the class manually if you need to store
something that doesn’t participate in the data flow (like a timer
ID).
We will tear down the timer in
the componentWillUnmount() lifecycle hook:
componentWillUnmount() {
clearInterval(this.timerID);
}
Finally, we will implement a method called tick() that
the Clock component will run every second.
It will use this.setState() to schedule updates to the
component local state:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is
{this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
Try it on CodePen
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.
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
}
The merging is shallow,
so this.setState({comments}) leaves this.state.postsi
ntact, but completely replaces this.state.comments.
ReactDOM.render(
<App />,
document.getElementById('root')
);
Try it on CodePen
Each Clock sets up its own timer and updates independently.
In React apps, whether a component is stateful or stateless is
considered an implementation detail of the component that may
change over time. You can use stateless components inside
stateful components, and vice versa.
• 6. Handling Events
return (
<a href="#" > Click me
</a>
);
}
Here, e is a synthetic event. React defines these synthetic
events according to the W3C spec, so you don’t need to worry
about cross-browser compatibility. See
the SyntheticEvent reference guide to learn more.
When using React you should generally not need to
call addEventListener to add listeners to a DOM element
after it is created. Instead, just provide a listener when the
element is initially rendered.
When you define a component using an ES6 class, a common
pattern is for an event handler to be a method on the class. For
example, this Toggle component renders a button that lets the
user toggle between “ON” and “OFF” states:
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
handleClick() {
this.setState(state => ({
isToggleOn: !state.isToggleOn
}));
}
render() {
return (
<button > {this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
Try it on CodePen
You have to be careful about the meaning of this in JSX
callbacks. In JavaScript, class methods are not bound by
default. If you forget to bind this.handleClick and pass it
to onClick, this will be undefined when the function is
actually called.
This is not React-specific behavior; it is a part of how functions
work in JavaScript. Generally, if you refer to a method
without () after it, such as >you should bind that method.
If calling bind annoys you, there are two ways you can get
around this. If you are using the experimental public class fields
syntax, you can use class fields to correctly bind callbacks:
class LoggingButton extends React.Component {
// This syntax ensures `this` is bound within
handleClick.
// Warning: this is *experimental* syntax.
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
<button > Click me
</button>
);
}
}
This syntax is enabled by default in Create React App.
If you aren’t using class fields syntax, you can use an arrow
function in the callback:
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// This syntax ensures `this` is bound within
handleClick
return (
<button => this.handleClick(e)}>
Click me
</button>
);
}
}
The problem with this syntax is that a different callback is
created each time the LoggingButton renders. In most cases,
this is fine. However, if this callback is passed as a prop to
lower components, those components might do an extra re-
rendering. We generally recommend binding in the constructor
or using the class fields syntax, to avoid this sort of
performance problem.
function GuestGreeting(props) {
return <h1>Please sign up.</h1>;
}
We’ll create a Greeting component that displays either of
these components depending on whether a user is logged in:
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
// Try changing to isLoggedIn={true}:
<Greeting isLoggedIn={false} />,
document.getElementById('root')
);
Try it on CodePen
This example renders a different greeting depending on the
value of isLoggedIn prop.
Element Variables
You can use variables to store elements. This can help you
conditionally render a part of the component while the rest of
the output doesn’t change.
Consider these two new components representing Logout and
Login buttons:
function LoginButton(props) {
return (
<button > Login
</button>
);
}
function LogoutButton(props) {
return (
<button > Logout
</button>
);
}
In the example below, we will create a stateful
component called LoginControl.
It will render either <LoginButton /> or <LogoutButton /
> depending on its current state. It will also render a <Greeting
/> from the previous example:
class LoginControl extends React.Component {
constructor(props) {
super(props);
this.handleLoginClick =
this.handleLoginClick.bind(this);
this.handleLogoutClick =
this.handleLogoutClick.bind(this);
this.state = {isLoggedIn: false};
}
handleLoginClick() {
this.setState({isLoggedIn: true});
}
handleLogoutClick() {
this.setState({isLoggedIn: false});
}
render() {
const isLoggedIn = this.state.isLoggedIn;
let button;
if (isLoggedIn) {
button = <LogoutButton
/>;
} else {
button = <LoginButton
/>
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}
}
ReactDOM.render(
<LoginControl />,
document.getElementById('root')
);
Try it on CodePen
While declaring a variable and using an if statement is a fine
way to conditionally render a component, sometimes you might
want to use a shorter syntax. There are a few ways to inline
conditions in JSX, explained below.
return (
<div className="warning">
Warning!
</div>
);
}
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {showWarning: true};
this.handleToggleClick =
this.handleToggleClick.bind(this);
}
handleToggleClick() {
this.setState(state => ({
showWarning: !state.showWarning
}));
}
render() {
return (
<div>
<WarningBanner warn={this.state.showWarning} />
<button > {this.state.showWarning ? 'Hide' : 'Show'}
</button>
</div>
);
}
}
ReactDOM.render(
<Page />,
document.getElementById('root')
);
Try it on CodePen
Returning null from a component’s render method does not
affect the firing of the component’s lifecycle methods. For
instance componentDidUpdate will still be called.
8. Lists and Keys
Keys
Keys help React identify which items have changed, are added,
or are removed. Keys should be given to the elements inside
the array to give the elements a stable identity:
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
The best way to pick a key is to use a string that uniquely
identifies a list item among its siblings. Most often you would
use IDs from your data as keys:
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);
When you don’t have stable IDs for rendered items, you may
use the item index as a key as a last resort:
const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs
<li key={index}>
{todo.text}
</li>
);
We don’t recommend using indexes for keys if the order of
items may change. This can negatively impact performance and
may cause issues with component state. Check out Robin
Pokorny’s article for an in-depth explanation on the negative
impacts of using an index as a key. If you choose not to assign
an explicit key to list items then React will default to using
indexes as keys.
Here is an in-depth explanation about why keys are
necessary if you’re interested in learning more.
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// Wrong! The key should have been specified here:
<ListItem value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// Correct! Key should be specified inside the array.
<ListItem key={number.toString()}
value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
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')
);
Try it on CodePen
Keys serve as a hint to React but they don’t get passed to your
components. If you need the same value in your component,
pass it explicitly as a prop with a different name:
const content = posts.map((post) =>
<Post
key={post.id}
id={post.id}
title={post.title} />
);
With the example above, the Post component can
read props.id, but not props.key.
Embedding map() in JSX
In the examples above we declared a
separate listItems variable and included it in JSX:
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<ListItem key={number.toString()}
value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
JSX allows embedding any expression in curly braces so we
could inline the map() result:
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{numbers.map((number) =>
<ListItem key={number.toString()}
value={number} />
)}
</ul>
);
}
Try it on CodePen
Sometimes this results in clearer code, but this style can also
be abused. Like in JavaScript, it is up to you to decide whether
it is worth extracting a variable for readability. Keep in mind that
if the map() body is too nested, it might be a good time
to extract a component.
9. Forms
HTML form elements work a little bit differently from other
DOM elements in React, because form elements naturally
keep some internal state. For example, this form in plain
HTML accepts a single name:
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
This form has the default HTML form behavior of browsing to a
new page when the user submits the form. If you want this
behavior in React, it just works. But in most cases, it’s
convenient to have a JavaScript function that handles the
submission of the form and has access to the data that the user
entered into the form. The standard way to achieve this is with a
technique called “controlled components”.
Controlled Components
In HTML, form elements such as <input>, <textarea>,
and <select> typically maintain their own state and update it
based on user input. In React, mutable state is typically kept in
the state property of components, and only updated
with setState().
We can combine the two by making the React state be the
“single source of truth”. Then the React component that renders
a form also controls what happens in that form on subsequent
user input. An input form element whose value is controlled by
React in this way is called a “controlled component”.
For example, if we want to make the previous example log the
name when it is submitted, we can write the form as a
controlled component:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form > <label>
Name:
<input type="text" value={this.state.value}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Try it on CodePen
Since the value attribute is set on our form element, the
displayed value will always be this.state.value, making the
React state the source of truth. Since handleChangeruns on
every keystroke to update the React state, the displayed value
will update as the user types.
With a controlled component, every state mutation will have an
associated handler function. This makes it straightforward to
modify or validate user input. For example, if we wanted to
enforce that names are written with all uppercase letters, we
could write handleChange as:
handleChange(event) {
this.setState({value:
event.target.value.toUpperCase()});
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('An essay was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form > <label>
Essay:
<textarea value={this.state.value}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Notice that this.state.value is initialized in the constructor,
so that the text area starts off with some text in it.
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('Your favorite flavor is: ' +
this.state.value);
event.preventDefault();
}
render() {
return (
<form > <label>
Pick your favorite flavor:
<select value={this.state.value}
> <option value="grapefruit">Grapefruit</
option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Try it on CodePen
Overall, this makes it so that <input
type="text">, <textarea>, and <select> all work very
similarly - they all accept a value attribute that you can use to
implement a controlled component.
Note
You can pass an array into the value attribute, allowing you to
select multiple options in a select tag:
<select multiple={true} value={['B', 'C']}>
this.handleInputChange =
this.handleInputChange.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ?
target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
return (
<form>
<label>
Is going:
<input
name="isGoing"
type="checkbox"
checked={this.state.isGoing}
/>
</label>
<br />
<label>
Number of guests:
<input
name="numberOfGuests"
type="number"
value={this.state.numberOfGuests}
/>
</label>
</form>
);
}
}
Try it on CodePen
Note how we used the ES6 computed property name syntax to
update the state key corresponding to the given input name:
this.setState({
[name]: value
});
It is equivalent to this ES5 code:
var partialState = {};
partialState[name] = value;
this.setState(partialState);
Also, since setState() automatically merges a partial state
into the current state, we only needed to call it with the changed
parts.
setTimeout(function() {
ReactDOM.render(<input value={null} />, mountNode);
}, 1000);
handleChange(e) {
this.setState({temperature: e.target.value});
}
render() {
const temperature = this.state.temperature;
return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input
value={temperature}
/>
<BoilingVerdict
celsius={parseFloat(temperature)} />
</fieldset>
);
}
}
Try it on CodePen
handleChange(e) {
this.setState({temperature: e.target.value});
}
render() {
const temperature = this.state.temperature;
const scale = this.props.scale;
return (
<fieldset>
<legend>Enter temperature in
{scaleNames[scale]}:</legend>
<input value={temperature}
/>
</fieldset>
);
}
}
We can now change the Calculator to render two separate
temperature inputs:
class Calculator extends React.Component {
render() {
return (
<div>
<TemperatureInput scale="c" />
<TemperatureInput scale="f" />
</div>
);
}
}
Try it on CodePen
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 also can’t display the BoilingVerdict from Calculator.
The Calculator doesn’t know the current temperature
because it is hidden inside the TemperatureInput.
function toFahrenheit(celsius) {
return (celsius * 9 / 5) + 32;
}
These two functions convert numbers. We will write another
function that takes a string temperature and a converter
function as arguments and returns a string. We will use it to
calculate the value of one input based on the other input.
It returns an empty string on an invalid temperature, and it
keeps the output rounded to the third decimal place:
function tryConvert(temperature, convert) {
const input = parseFloat(temperature);
if (Number.isNaN(input)) {
return '';
}
const output = convert(input);
const rounded = Math.round(output * 1000) / 1000;
return rounded.toString();
}
For example, tryConvert('abc', toCelsius) returns an
empty string, and tryConvert('10.22',
toFahrenheit) returns '50.396'.
Lifting State Up
Currently, both TemperatureInput components independently
keep their values in the local state:
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''};
}
handleChange(e) {
this.setState({temperature: e.target.value});
}
render() {
const temperature = this.state.temperature;
// ...
However, we want these two inputs to be in sync with each
other. When we update the Celsius input, the Fahrenheit input
should reflect the converted temperature, and vice versa.
In React, sharing state is accomplished by moving it up to the
closest common ancestor of the components that need it. This
is called “lifting state up”. We will remove the local state from
the TemperatureInput and move it into
the Calculator instead.
If the Calculator owns the shared state, it becomes the
“source of truth” for the current temperature in both inputs. It
can instruct them both to have values that are consistent with
each other. Since the props of
both TemperatureInput components are coming from the
same parent Calculator component, the two inputs will
always be in sync.
Let’s see how this works step by step.
First, we will
replace this.state.temperature with this.props.temper
ature in the TemperatureInput component. For now, let’s
pretend this.props.temperaturealready exists, although we
will need to pass it from the Calculator in the future:
render() {
// Before: const temperature =
this.state.temperature;
const temperature = this.props.temperature;
// ...
We know that props are read-only. When the temperature was
in the local state, the TemperatureInput could just
call this.setState() to change it. However, now that
the temperature is coming from the parent as a prop,
the TemperatureInput has no control over it.
In React, this is usually solved by making a component
“controlled”. Just like the DOM <input> accepts both
a value and an onChange prop, so can the
custom TemperatureInput accept
both temperature and onTemperatureChange props from its
parent Calculator.
Now, when the TemperatureInput wants to update its
temperature, it calls this.props.onTemperatureChange:
handleChange(e) {
// Before: this.setState({temperature:
e.target.value});
this.props.onTemperatureChange(e.target.value);
// ...
Note:
There is no special meaning to
either temperature or onTemperatureChange prop names in
custom components. We could have called them anything else,
like name them value and onChange which is a common
convention.
The onTemperatureChange prop will be provided together with
the temperature prop by the parent Calculator component.
It will handle the change by modifying its own local state, thus
re-rendering both inputs with the new values. We will look at the
new Calculator implementation very soon.
Before diving into the changes in the Calculator, let’s recap
our changes to the TemperatureInput component. We have
removed the local state from it, and instead of
reading this.state.temperature, we now
read this.props.temperature. Instead of
calling this.setState() when we want to make a change, we
now call this.props.onTemperatureChange(), which will be
provided by the Calculator:
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.props.onTemperatureChange(e.target.value);
}
render() {
const temperature = this.props.temperature;
const scale = this.props.scale;
return (
<fieldset>
<legend>Enter temperature in
{scaleNames[scale]}:</legend>
<input value={temperature}
/>
</fieldset>
);
}
}
Now let’s turn to the Calculator component.
We will store the current input’s temperature and scale in its
local state. This is the state we “lifted up” from the inputs, and it
will serve as the “source of truth” for both of them. It is the
minimal representation of all the data we need to know in order
to render both inputs.
For example, if we enter 37 into the Celsius input, the state of
the Calculator component will be:
{
temperature: '37',
scale: 'c'
}
If we later edit the Fahrenheit field to be 212, the state of
the Calculator will be:
{
temperature: '212',
scale: 'f'
}
We could have stored the value of both inputs but it turns out to
be unnecessary. It is enough to store the value of the most
recently changed input, and the scale that it represents. We can
then infer the value of the other input based on the
current temperature and scale alone.
The inputs stay in sync because their values are computed from
the same state:
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleCelsiusChange =
this.handleCelsiusChange.bind(this);
this.handleFahrenheitChange =
this.handleFahrenheitChange.bind(this);
this.state = {temperature: '', scale: 'c'};
}
handleCelsiusChange(temperature) {
this.setState({scale: 'c', temperature});
}
handleFahrenheitChange(temperature) {
this.setState({scale: 'f', temperature});
}
render() {
const scale = this.state.scale;
const temperature = this.state.temperature;
const celsius = scale === 'f' ?
tryConvert(temperature, toCelsius) : temperature;
const fahrenheit = scale === 'c' ?
tryConvert(temperature, toFahrenheit) : temperature;
return (
<div>
<TemperatureInput
scale="c"
temperature={celsius}
/>
<TemperatureInput
scale="f"
temperature={fahrenheit}
/>
<BoilingVerdict
celsius={parseFloat(celsius)} />
</div>
);
}
}
Try it on CodePen
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.
Let’s recap what happens when you edit an input:
• React calls the function specified as onChange on the DOM <input>. In
our case, this is the handleChange method in
the TemperatureInput component.
• The handleChange method in the TemperatureInput component
calls this.props.onTemperatureChange() with the new
desired value. Its props, including onTemperatureChange, were
provided by its parent component, the Calculator.
• When it previously rendered, the Calculator has specified
that onTemperatureChangeof the
Celsius TemperatureInput is
the Calculator’s handleCelsiusChangemethod,
and onTemperatureChange of the
Fahrenheit TemperatureInput is
the Calculator’s handleFahrenheitChange method. So either
of these two Calculatormethods gets called depending on which input we
edited.
• Inside these methods, the Calculator component asks React to re-render
itself by calling this.setState() with the new input value and the current
scale of the input we just edited.
• React calls the Calculator component’s render method to learn what
the UI should look like. The values of both inputs are recomputed based on the
current temperature and the active scale. The temperature conversion is performed
here.
• React calls the render methods of the
individual TemperatureInput components with their new props specified
by the Calculator. It learns what their UI should look like.
• React calls the render method of the BoilingVerdict component,
passing the temperature in Celsius as its props.
• React DOM updates the DOM with the boiling verdict and to match the desired
input values. The input we just edited receives its current value, and the other input
is updated to the temperature after conversion.
Every update goes through the same steps so the inputs stay in
sync.
Lessons Learned
There should be a single “source of truth” for any data that
changes in a React application. Usually, the state is first added
to the component that needs it for rendering. Then, if other
components also need it, you can lift it up to their closest
common ancestor. Instead of trying to sync the state between
different components, you should rely on the top-down data
flow.
Lifting state involves writing more “boilerplate” code than two-
way binding approaches, but as a benefit, it takes less work to
find and isolate bugs. Since any state “lives” in some
component and that component alone can change it, the
surface area for bugs is greatly reduced. Additionally, you can
implement any custom logic to reject or transform user input.
If something can be derived from either props or state, it
probably shouldn’t be in the state. For example, instead of
storing both celsiusValue and fahrenheitValue, we store
just the last edited temperature and its scale. The value of
the other input can always be calculated from them in
the render() method. This lets us clear or apply rounding to
the other field without losing any precision in the user input.
When you see something wrong in the UI, you can use React
Developer Tools to inspect the props and move up the tree until
you find the component responsible for updating the state. This
lets you trace the bugs to their source:
Containment
Some components don’t know their children ahead of time. This
is especially common for components
like Sidebar or Dialog that represent generic “boxes”.
We recommend that such components use the
special children prop to pass children elements directly into
their output:
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' +
props.color}>
{props.children}
</div>
);
}
This lets other components pass arbitrary children to them by
nesting the JSX:
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
Welcome
</h1>
<p className="Dialog-message">
Thank you for visiting our spacecraft!
</p>
</FancyBorder>
);
}
Try it on CodePen
Anything inside the <FancyBorder> JSX tag gets passed into
the FancyBordercomponent as a children prop.
Since FancyBorder renders {props.children} inside
a <div>, the passed elements appear in the final output.
While this is less common, sometimes you might need multiple
“holes” in a component. In such cases you may come up with
your own convention instead of using children:
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}
function App() {
return (
<SplitPane
left={
<Contacts />
}
right={
<Chat />
} />
);
}
Try it on CodePen
React elements like <Contacts /> and <Chat /> are just
objects, so you can pass them as props like any other data.
This approach may remind you of “slots” in other libraries but
there are no limitations on what you can pass as props in
React.
Specialization
Sometimes we think about components as being “special
cases” of other components. For example, we might say that
a WelcomeDialog is a special case of Dialog.
In React, this is also achieved by composition, where a more
“specific” component renders a more “generic” one and
configures it with props:
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
</FancyBorder>
);
}
function WelcomeDialog() {
return (
<Dialog
title="Welcome"
message="Thank you for visiting our spacecraft!" />
);
}
Try it on CodePen
Composition works equally well for components defined as
classes:
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
{props.children}
</FancyBorder>
);
}
render() {
return (
<Dialog title="Mars Exploration Program"
message="How should we refer to you?">
<input value={this.state.login}
/>
<button > Sign Me Up!
</button>
</Dialog>
);
}
handleChange(e) {
this.setState({login: e.target.value});
}
handleSignUp() {
alert(`Welcome aboard, ${this.state.login}!`);
}
}
Try it on CodePen
React is, in our opinion, the premier way to build big, fast
Web apps with JavaScript. It has scaled very well for us at
Facebook and Instagram.
One of the many great parts of React is how it makes you think
about apps as you build them. In this document, we’ll walk you
through the thought process of building a searchable product
data table using React.
Our JSON API returns some data that looks like this:
[
{category: "Sporting Goods", price: "$49.99", stocked:
true, name: "Football"},
{category: "Sporting Goods", price: "$9.99", stocked:
true, name: "Baseball"},
{category: "Sporting Goods", price: "$29.99", stocked:
false, name: "Basketball"},
{category: "Electronics", price: "$99.99", stocked:
true, name: "iPod Touch"},
{category: "Electronics", price: "$399.99", stocked:
false, name: "iPhone 5"},
{category: "Electronics", price: "$199.99", stocked:
true, name: "Nexus 7"}
];
Step 1: Break The UI Into A Component Hierarchy
The first thing you’ll want to do is to draw boxes around every
component (and subcomponent) in the mock and give them all
names. If you’re working with a designer, they may have
already done this, so go talk to them! Their Photoshop layer
names may end up being the names of your React
components!
But how do you know what should be its own component? Just
use the same techniques for deciding if you should create a
new function or object. One such technique is the single
responsibility principle, that is, a component should ideally only
do one thing. If it ends up growing, it should be decomposed
into smaller subcomponents.
Since you’re often displaying a JSON data model to a user,
you’ll find that if your model was built correctly, your UI (and
therefore your component structure) will map nicely. That’s
because UI and data models tend to adhere to the
same information architecture, which means the work of
separating your UI into components is often trivial. Just break it
up into components that represent exactly one piece of your
data model.
You’ll see here that we have five components in our simple app.
We’ve italicized the data each component represents.
1. FilterableProductTable (orange): contains the entirety of the example
2. SearchBar (blue): receives all user input
3. ProductTable (green): displays and filters the data collection based on user input
4. ProductCategoryRow (turquoise): displays a heading for each category
5. ProductRow (red): displays a row for each product
If you look at ProductTable, you’ll see that the table header
(containing the “Name” and “Price” labels) isn’t its own
component. This is a matter of preference, and there’s an
argument to be made either way. For this example, we left it as
part of ProductTablebecause it is part of rendering the data
collection which is ProductTable’s responsibility. However, if
this header grows to be complex (i.e. if we were to add
affordances for sorting), it would certainly make sense to make
this its own ProductTableHeader component.
Now that we’ve identified the components in our mock, let’s
arrange them into a hierarchy. This is easy. Components that
appear within another component in the mock should appear as
a child in the hierarchy:
• FilterableProductTable
• SearchBar
• ProductTable
• ProductCategoryRow
• ProductRow
Higher-Order Components
A higher-order component (HOC) is an advanced technique
in React for reusing component logic. HOCs are not part of
the React API, per se. They are a pattern that emerges from
React’s compositional nature.
Concretely, a higher-order component is a function that
takes a component and returns a new component.
const EnhancedComponent =
higherOrderComponent(WrappedComponent);
Whereas a component transforms props into UI, a higher-order
component transforms a component into another component.
HOCs are common in third-party React libraries, such as
Redux’s connect and Relay’s createFragmentContainer.
In this document, we’ll discuss why higher-order components
are useful, and how to write your own.
componentDidMount() {
// Subscribe to changes
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
// Clean up listener
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
// Update component state whenever the data source
changes
this.setState({
comments: DataSource.getComments()
});
}
render() {
return (
<div>
{this.state.comments.map((comment) => (
<Comment comment={comment} key={comment.id} />
))}
</div>
);
}
}
Later, you write a component for subscribing to a single blog
post, which follows a similar pattern:
class BlogPost extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
blogPost: DataSource.getBlogPost(props.id)
};
}
componentDidMount() {
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
this.setState({
blogPost: DataSource.getBlogPost(this.props.id)
});
}
render() {
return <TextBlock text={this.state.blogPost} />;
}
}
CommentList and BlogPost aren’t identical — they call
different methods on DataSource, and they render different
output. But much of their implementation is the same:
• On mount, add a change listener to DataSource.
• Inside the listener, call setState whenever the data source changes.
• On unmount, remove the change listener.
You can imagine that in a large app, this same pattern of
subscribing to DataSource and calling setState will occur
over and over again. We want an abstraction that allows us to
define this logic in a single place and share it across many
components. This is where higher-order components excel.
We can write a function that creates components,
like CommentList and BlogPost, that subscribe
to DataSource. The function will accept as one of its
arguments a child component that receives the subscribed data
as a prop. Let’s call the function withSubscription:
const CommentListWithSubscription = withSubscription(
CommentList,
(DataSource) => DataSource.getComments()
);
componentDidMount() {
// ... that takes care of the subscription...
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
this.setState({
data: selectData(DataSource, this.props)
});
}
render() {
// ... and renders the wrapped component with the
fresh data!
// Notice that we pass through any additional props
return <WrappedComponent data={this.state.data}
{...this.props} />;
}
};
}
Note that a HOC doesn’t modify the input component, nor does
it use inheritance to copy its behavior. Rather, a
HOC composes the original component by wrapping it in a
container component. A HOC is a pure function with zero side-
effects.
And that’s it! The wrapped component receives all the props of
the container, along with a new prop, data, which it uses to
render its output. The HOC isn’t concerned with how or why the
data is used, and the wrapped component isn’t concerned with
where the data came from.
Because withSubscription is a normal function, you can add
as many or as few arguments as you like. For example, you
may want to make the name of the data prop configurable, to
further isolate the HOC from the wrapped component. Or you
could accept an argument that
configures shouldComponentUpdate, or one that configures
the data source. These are all possible because the HOC has
full control over how the component is defined.
Like components, the contract
between withSubscription and the wrapped component is
entirely props-based. This makes it easy to swap one HOC for a
different one, as long as they provide the same props to the
wrapped component. This may be useful if you change data-
fetching libraries, for example.
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName ||
WrappedComponent.name || 'Component';
}
Caveats
Higher-order components come with a few caveats that aren’t
immediately obvious if you’re new to React.
JSX In Depth
Fundamentally, JSX just provides syntactic sugar for
the React.createElement(component,
props, ...children) function. The JSX code:
<MyButton color="blue" shadowSize={2}>
Click Me
</MyButton>
compiles into:
React.createElement(
MyButton,
{color: 'blue', shadowSize: 2},
'Click Me'
)
You can also use the self-closing form of the tag if there are no
children. So:
<div className="sidebar" />
compiles into:
React.createElement(
'div',
{className: 'sidebar'},
null
)
If you want to test out how some specific JSX is converted into
JavaScript, you can try out the online Babel compiler.
function WarningButton() {
// return React.createElement(CustomButton, {color:
'red'}, null);
return <CustomButton color="red" />;
}
If you don’t use a JavaScript bundler and loaded React from
a <script> tag, it is already in scope as the React global.
const MyComponents = {
DatePicker: function DatePicker(props) {
return <div>Imagine a {props.color} datepicker
here.</div>;
}
}
function BlueDatePicker() {
return <MyComponents.DatePicker color="blue" />;
}
function HelloWorld() {
// Wrong! React thinks <hello /> is an HTML tag because
it's not capitalized:
return <hello toWhat="World" />;
}
To fix this, we will rename hello to Hello and use <Hello /
> when referring to it:
import React from 'react';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Wrong! JSX type can't be an expression.
return <components[props.storyType] story={props.story}
/>;
}
To fix this, we will assign the type to a capitalized variable first:
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// Correct! JSX type can be a capitalized variable.
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />;
}
Props in JSX
There are several different ways to specify props in JSX.
Spread Attributes
If you already have props as an object, and you want to pass it
in JSX, you can use ...as a “spread” operator to pass the
whole props object. These two components are equivalent:
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}
You can also pick specific props that your component will
consume while passing all other props using the spread
operator.
const Button = props => {
const { kind, ...other } = props;
const className = kind === "primary" ?
"PrimaryButton" : "SecondaryButton";
return <button className={className} {...other} />;
};
Children in JSX
In JSX expressions that contain both an opening tag and a
closing tag, the content between those tags is passed as a
special prop: props.children. There are several different
ways to pass children:
String Literals
You can put a string between the opening and closing tags
and props.children will just be that string. This is useful for
many of the built-in HTML elements. For example:
<MyComponent>Hello world!</MyComponent>
This is valid JSX, and props.children in MyComponent will
simply be the string "Hello world!". HTML is unescaped, so
you can generally write JSX just like you would write HTML in
this way:
<div>This is valid HTML & JSX at the same time.</div>
JSX removes whitespace at the beginning and ending of a line.
It also removes blank lines. New lines adjacent to tags are
removed; new lines that occur in the middle of string literals are
condensed into a single space. So these all render to the same
thing:
<div>Hello World</div>
<div>
Hello World
</div>
<div>
Hello
World
</div>
<div>
Hello World
</div>
JSX Children
You can provide more JSX elements as the children. This is
useful for displaying nested components:
<MyContainer>
<MyFirstComponent />
<MySecondComponent />
</MyContainer>
You can mix together different types of children, so you can use
string literals together with JSX children. This is another way in
which JSX is like HTML, so that this is both valid JSX and valid
HTML:
<div>
Here is a list:
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
A React component can also return an array of elements:
render() {
// No need to wrap list items in an extra element!
return [
// Don't forget the keys :)
<li key="A">First item</li>,
<li key="B">Second item</li>,
<li key="C">Third item</li>,
];
}
<MyComponent>{'foo'}</MyComponent>
This is often useful for rendering a list of JSX expressions of
arbitrary length. For example, this renders an HTML list:
function Item(props) {
return <li>{props.message}</li>;
}
function TodoList() {
const todos = ['finish doc', 'submit pr', 'nag dan to
review'];
return (
<ul>
{todos.map((message) => <Item key={message}
message={message} />)}
</ul>
);
}
JavaScript expressions can be mixed with other types of
children. This is often useful in lieu of string templates:
function Hello(props) {
return <div>Hello {props.addressee}!</div>;
}
Functions as Children
Normally, JavaScript expressions inserted in JSX will evaluate
to a string, a React element, or a list of those things.
However, props.children works just like any other prop in
that it can pass any sort of data, not just the sorts that React
knows how to render. For example, if you have a custom
component, you could have it take a callback
as props.children:
// Calls the children callback numTimes to produce a
repeated component
function Repeat(props) {
let items = [];
for (let i = 0; i < props.numTimes; i++) {
items.push(props.children(i));
}
return <div>{items}</div>;
}
function ListOfTenThings() {
return (
<Repeat numTimes={10}>
{(index) => <div key={index}>This is item {index}
in the list</div>}
</Repeat>
);
}
Children passed to a custom component can be anything, as
long as that component transforms them into something React
can understand before rendering. This usage is not common,
but it works if you want to stretch what JSX is capable of.
<div></div>
<div>{false}</div>
<div>{null}</div>
<div>{undefined}</div>
<div>{true}</div>
This can be useful to conditionally render React elements. This
JSX only renders a <Header /> if showHeader is true:
<div>
{showHeader && <Header />}
<Content />
</div>
One caveat is that some “falsy” values, such as the 0 number,
are still rendered by React. For example, this code will not
behave as you might expect because 0 will be printed
when props.messages is an empty array:
<div>
{props.messages.length &&
<MessageList messages={props.messages} />
}
</div>
To fix this, make sure that the expression before && is always
boolean:
<div>
{props.messages.length > 0 &&
<MessageList messages={props.messages} />
}
</div>
Conversely, if you want a value like false, true, null,
or undefined to appear in the output, you have to convert it to
a string first:
<div>
My JavaScript variable is {String(myVariable)}.
</div>