Consider the ticking clock example from one of the previous sections. In Rendering Elements, we have only learned one way to update the UI. We call
root.render()
to change the rendered output:
functiontick(){ const element =( <div> <h1>Hello, world!</h1> <h2>It is {newDate().toLocaleTimeString()}.</h2> </div> ); root.render(element);}
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:
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:
root.render(<Clock/>);
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.
Converting a Function to a Class
You can convert a function component like
Clock
to a class in five steps:
Create an ES6 class, with the same name, that extends
React.Component
.
Add a single empty method to it called
render()
.
Move the body of the function into the
render()
method.
Replace
props
with
this.props
in the
render()
body.
Clock
is now defined as a class rather than a function.
The
render
method will be called each time an update happens, but as long as we render
<Clock />
into the same DOM node, only a single instance of the
Clock
class will be used. This lets us use additional features such as local state and lifecycle methods.
Adding Local State to a Class
We will move the
date
from props to state in three steps:
Replace
this.props.date
with
this.state.date
in the
render()
method:
Note how we save the timer ID right on
this
(
this.timerID
).
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 method:
Let’s quickly recap what’s going on and the order in which the methods are called:
When
<Clock />
is passed to
root.render()
, React calls the constructor of the
Clock
component. Since
Clock
needs to display the current time, it initializes
this.state
with an object including the current time. We will later update this state.
React then calls the
Clock
component’s
render()
method. This is how React learns what should be displayed on the screen. React then updates the DOM to match the
Clock
’s render output.
When the
Clock
output is inserted in the DOM, React calls the
componentDidMount()
lifecycle method. Inside it, the
Clock
component asks the browser to set up a timer to call the component’s
tick()
method once a second.
Every second the browser calls the
tick()
method. Inside it, the
Clock
component schedules a UI update by calling
setState()
with an object containing the current time. Thanks to the
setState()
call, React knows the state has changed, and calls the
render()
method again to learn what should be on the screen. This time,
this.state.date
in the
render()
method will be different, and so the render output will include the updated time. React updates the DOM accordingly.
If the
Clock
component is ever removed from the DOM, React calls the
componentWillUnmount()
lifecycle method so the timer is stopped.
Using State Correctly
There are three things you should know about
setState()
.
Do Not Modify State Directly
For example, this will not re-render a component:
// Wrong this.state.comment ='Hello';
Instead, use
setState()
:
// Correct this.setState({comment:'Hello'});
The only place where you can assign
this.state
is the constructor.
State Updates May Be Asynchronous
React may batch multiple
setState()
calls into a single update for performance.
Because
this.props
and
this.state
may be updated asynchronously, you should not rely on their values for calculating the next state.
For example, this code may fail to update the counter:
To fix it, use a second form of
setState()
that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
The merging is shallow, so
this.setState({comments})
leaves
this.state.posts
intact, but completely replaces
this.state.comments
.
The Data Flows Down
Neither parent nor child components can know if a certain component is stateful or stateless, and they shouldn’t care whether it is defined as a function or a class.
This is why state is often called local or encapsulated. It is not accessible to any component other than the one that owns and sets it.
A component may choose to pass its state down as props to its child components:
<FormattedDatedate={this.state.date}/>
The
FormattedDate
component would receive the
date
in its props and wouldn’t know whether it came from the
Clock
’s state, from the
Clock
’s props, or was typed by hand:
functionFormattedDate(props){ return<h2>It is {props.date.toLocaleTimeString()}.</h2>; }
Try it on CodePen
This is commonly called a “top-down” or “unidirectional” data flow. Any state is always owned by some specific component, and any data or UI derived from that state can only affect components “below” them in the tree.
If you imagine a component tree as a waterfall of props, each component’s state is like an additional water source that joins it at an arbitrary point but also flows down.
To show that all components are truly isolated, we can create an
App
component that renders three
<Clock>
s:
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.
Is this page useful?
Edit this page
Handling Events – React
Handling Events
Handling events with React elements is very similar to handling events on DOM elements. There are some syntax differences:
React events are named using camelCase, rather than lowercase.
With JSX you pass a function as the event handler, rather than a string.
Another difference is that you cannot return
false
to prevent default behavior in React. You must call
preventDefault
explicitly. For example, with plain HTML, to prevent the default form behavior of submitting, you can write:
When using React, you generally don’t 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:
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
onClick={this.handleClick}
, you should bind that method.
If calling
bind
annoys you, there are two ways you can get around this. You can use public class fields syntax to correctly bind callbacks:
classLoggingButtonextendsReact.Component{ // This syntax ensures `this` is bound within handleClick.handleClick=()=>{ console.log('this is:',this);};render(){ return( <buttononClick={this.handleClick}> 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:
render(){ // This syntax ensures `this` is bound within handleClickreturn(<buttononClick={()=>this.handleClick()}> 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.
Passing Arguments to Event Handlers
Inside a loop, it is common to want to pass an extra parameter to an event handler. For example, if
id
is the row ID, either of the following would work:
The above two lines are equivalent, and use arrow functions and
Function.prototype.bind
respectively.
In both cases, the
e
argument representing the React event will be passed as a second argument after the ID. With an arrow function, we have to pass it explicitly, but with
bind
any further arguments are automatically forwarded.
In React, you can create distinct components that encapsulate behavior you need. Then, you can render only some of them, depending on the state of your application.
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:
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.
Inline If with Logical && Operator
You may embed expressions in JSX by wrapping them in curly braces. This includes the JavaScript logical
&&
operator. It can be handy for conditionally including an element:
functionMailbox(props){ const unreadMessages = props.unreadMessages; return( <div> <h1>Hello!</h1> {unreadMessages.length >0&&<h2> You have {unreadMessages.length} unread messages.</h2>}</div> ); }
It works because in JavaScript,
true && expression
always evaluates to
expression
, and
false && expression
always evaluates to
false
.
Therefore, if the condition is
true
, the element right after
&&
will appear in the output. If it is
false
, React will ignore and skip it.
Note that returning a falsy expression will still cause the element after
&&
to be skipped but will return the falsy expression. In the example below,
<div>0</div>
will be returned by the render method.
Just like in JavaScript, it is up to you to choose an appropriate style based on what you and your team consider more readable. Also remember that whenever conditions become too complex, it might be a good time to extract a component.
Preventing Component from Rendering
In rare cases you might want a component to hide itself even though it was rendered by another component. To do this return
null
instead of its render output.
In the example below, the
<WarningBanner />
is rendered depending on the value of the prop called
warn
. If the value of the prop is
false
, then the component does not render:
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.
const numbers =[1,2,3,4,5]; const doubled = numbers.map((number)=> number *2);console.log(doubled);
This code logs
[2, 4, 6, 8, 10]
to the console.
In React, transforming arrays into lists of elements is nearly identical.
Rendering Multiple Components
You can build collections of elements and include them in JSX using curly braces
{}
.
Below, we loop through the
numbers
array using the JavaScript
map()
function. We return a
<li>
element for each item. Finally, we assign the resulting array of elements to
listItems
:
When you run this code, you’ll be given a warning that a key should be provided for list items. A “key” is a special string attribute you need to include when creating lists of elements. We’ll discuss why it’s important in the next section.
Let’s assign a
key
to our list items inside
numbers.map()
and fix the missing key issue.
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:
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:
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<likey={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.
Extracting Components with Keys
Keys only make sense in the context of the surrounding array.
For example, if you extract a
ListItem
component, you should keep the key on the
<ListItem />
elements in the array rather than on the
<li>
element in the
ListItem
itself.
Example: Incorrect Key Usage
functionListItem(props){ const value = props.value; return( // Wrong! There is no need to specify the key here:<likey={value.toString()}>{value} </li> ); }
functionNumberList(props){ const numbers = props.numbers; const listItems = numbers.map((number)=> // Wrong! The key should have been specified here:<ListItemvalue={number}/>); return( <ul> {listItems} </ul> ); }
Example: Correct Key Usage
functionListItem(props){ // Correct! There is no need to specify the key here:return<li>{props.value}</li>;}
functionNumberList(props){ const numbers = props.numbers; const listItems = numbers.map((number)=> // Correct! Key should be specified inside the array.<ListItemkey={number.toString()}value={number}/>); return( <ul> {listItems} </ul> ); }
Try it on CodePen
A good rule of thumb is that elements inside the
map()
call need keys.
Keys Must Only Be Unique Among Siblings
Keys used within arrays should be unique among their siblings. However, they don’t need to be globally unique. We can use the same keys when we produce two different arrays:
const posts =[ {id:1,title:'Hello World',content:'Welcome to learning React!'}, {id:2,title:'Installation',content:'You can install React from npm.'} ];
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:
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.
HTML form elements work a 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:
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”.
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:
handleChange(event){this.setState({value: event.target.value});} handleSubmit(event){ alert('A name was submitted: '+this.state.value); event.preventDefault(); }
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
handleChange
runs on every keystroke to update the React state, the displayed value will update as the user types.
With a controlled component, the input’s value is always driven by the React state. While this means you have to type a bit more code, you can now pass the value to other UI elements too, or reset it from other event handlers.
The textarea Tag
In HTML, a
<textarea>
element defines its text by its children:
<textarea> Hello there, this is some text in a text area </textarea>
In React, a
<textarea>
uses a
value
attribute instead. This way, a form using a
<textarea>
can be written very similarly to a form that uses a single-line input:
classEssayFormextendsReact.Component{ constructor(props){ super(props); this.state ={value:'Please write an essay about your favorite DOM element.'}; 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(); }
Note that the Coconut option is initially selected, because of the
selected
attribute. React, instead of using this
selected
attribute, uses a
value
attribute on the root
select
tag. This is more convenient in a controlled component because you only need to update it in one place. For example:
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:
<selectmultiple={true}value={['B','C']}>
The file input Tag
In HTML, an
<input type="file">
lets the user choose one or more files from their device storage to be uploaded to a server or manipulated by JavaScript via the File API.
<inputtype="file"/>
Because its value is read-only, it is an
uncontrolled
component in React. It is discussed together with other uncontrolled components later in the documentation.
Handling Multiple Inputs
When you need to handle multiple controlled
input
elements, you can add a
name
attribute to each element and let the handler function choose what to do based on the value of
event.target.name
.
render(){ return( <form> <label> Is going: <input name="isGoing"type="checkbox" checked={this.state.isGoing} onChange={this.handleInputChange}/> </label> <br/> <label> Number of guests: <input name="numberOfGuests"type="number" value={this.state.numberOfGuests} onChange={this.handleInputChange}/> </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.
Controlled Input Null Value
Specifying the
value
prop on a controlled component prevents the user from changing the input unless you desire so. If you’ve specified a
value
but the input is still editable, you may have accidentally set
value
to
undefined
or
null
.
The following code demonstrates this. (The input is locked at first but becomes editable after a short delay.)
It can sometimes be tedious to use controlled components, because you need to write an event handler for every way your data can change and pipe all of the input state through a React component. This can become particularly annoying when you are converting a preexisting codebase to React, or integrating a React application with a non-React library. In these situations, you might want to check out uncontrolled components, an alternative technique for implementing input forms.
Fully-Fledged Solutions
If you’re looking for a complete solution including validation, keeping track of the visited fields, and handling form submission, Formik is one of the popular choices. However, it is built on the same principles of controlled components and managing state — so don’t neglect to learn them.
Often, several components need to reflect the same changing data. We recommend lifting the shared state up to their closest common ancestor. Let’s see how this works in action.
In this section, we will create a temperature calculator that calculates whether the water would boil at a given temperature.
We will start with a component called
BoilingVerdict
. It accepts the
celsius
temperature as a prop, and prints whether it is enough to boil the water:
functionBoilingVerdict(props){ if(props.celsius >=100){ return<p>The water would boil.</p>;} return<p>The water would not boil.</p>;}
Next, we will create a component called
Calculator
. It renders an
<input>
that lets you enter the temperature, and keeps its value in
this.state.temperature
.
Additionally, it renders the
BoilingVerdict
for the current input value.
render(){ const temperature =this.state.temperature;return( <fieldset> <legend>Enter temperature in Celsius:</legend> <inputvalue={temperature}onChange={this.handleChange}/><BoilingVerdictcelsius={parseFloat(temperature)}/></fieldset> ); } }
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
.
Writing Conversion Functions
First, we will write two functions to convert from Celsius to Fahrenheit and back:
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:
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.temperature
in the
TemperatureInput
component. For now, let’s pretend
this.props.temperature
already 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
:
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
:
render(){ const temperature =this.props.temperature;const scale =this.props.scale; return( <fieldset> <legend>Enter temperature in {scaleNames[scale]}:</legend> <inputvalue={temperature} onChange={this.handleChange}/> </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:
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
had specified that
onTemperatureChange
of the Celsius
TemperatureInput
is the
Calculator
’s
handleCelsiusChange
method, and
onTemperatureChange
of the Fahrenheit
TemperatureInput
is the
Calculator
’s
handleFahrenheitChange
method. So either of these two
Calculator
methods 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: