State
Definition
A component needs state when some data associated with it changes over time. For example, a Checkbox component might need isChecked in its state, and a NewsFeed component might want to keep track of fetchedPosts in its state.
The most important difference between state and props is that props are passed from a parent component, but state is managed by the component itself. A component cannot change its props, but it can change its state.
For each particular piece of changing data, there should be just one component that “owns” it in its state. Don’t try to synchronize states of two different components. Instead, lift it up to their closest shared ancestor, and pass it down as props to both of them. Just an object that lives inside a component and stores all of the data that that component and maybe some of its children need.
State is local to the component (encapsulated) and should not be accessed outside the component.
State in Function Components
useState
Hook
Using the state
Defining main.js
state
Setting main.js
state
directly, use the setter function returned by the hook.
Remember not to set main.js
FAQs
What does calling useState do?
It declares a “state variable”. Our variable is called time
but we could call it anything else, like basketball
. This is a way to “preserve” some values between the function calls — useState
is a new way to use the exact same capabilities that this.state provides in a class. Normally, variables “disappear” when the function exits but state variables are preserved by React.
What do we pass to useState as an argument?
The only argument to the useState()
Hook is the initial state
. Unlike with classes, the state doesn’t have to be an object. We can keep a number or a string if that’s all we need. In our example, we just want a date object to show the time, so we pass the a new date object (now) as initial state for our variable. (If we wanted to store two different values in state, we would call useState() twice.)
What does useState return?
It returns a pair of values: the current state and a function that updates it. This is why we write const [date, setDate] = useState(...). This is similar to this.state.count
and this.setState
in a class, except you get them in a pair.
What is that syntax?
The syntax for useState
is confusing at first because it uses Array destructuring to return a pair. Array destructuring is used because it allows the us to decide what the variable and setter function should be named.
useState
Where to use In Classes | With Hooks |
---|---|
this.setState | useState |
useState
don’t work inside classes. But you can use function components with hooks instead of class components andsetState
.
Using Multiple State Variables
Declaring state variables as a pair of [something, setSomething]
is also handy because it lets us give different names to different state variables if we want to use more than one:
In the above component, we have age
, fruit
, and todos
as local variables, and we can update them individually:
You don’t have to use many state variables. State variables can hold objects and arrays just fine, so you can still group related data together. However, unlike this.setState
in a class, updating a state variable always replaces it instead of merging it.
Should I use one or many state variables?
If you’re coming from classes, you might be tempted to always call useState()
once and put all state into a single object. You can do it if you’d like. Here is an example of a component that follows the mouse movement. We keep its position and size in the local state:
Now let’s say we want to write some logic that changes left and top when the user moves their mouse. Note how we have to merge these fields into the previous state object manually:
This is because when we update a state variable, we replace its value. This is different from this.setState
in a class, which merges the updated fields into the object.
The React team recommends to split state into multiple state variables based on which values tend to change together.
For example, we could split our component state into position and size objects, and always replace the position with no need for merging:
Common State Use Case
state
using the current state
or props
Setting Use a Functional update
If the new state is computed using the previous state, you can pass a function to setState. The function will receive the previous value, and return an updated value. Here’s an example of a counter component that uses both forms of setState:
The ”Increment” and ”Increment Function Update” buttons use the two different forms of updating state. This is not an issue until you set state repeatedly. The issue arises because React does state updates asyncronously and can batch them to improve rendering performance.
How to be sure a setState call has completed?
Use a useEffect
hook with a dependency on the the state variable that is changing. We will learn about useEffect
in the next chapter.
State in Class Components
In React, you don’t manipulate the DOM directly, instead you simply update data (state) and let React react by updating the UI in all the needed places.
To make it easier to read and understand, the last example uses class field declarations which is not an official feature of JavaScript but is currently a Stage 3 proposal
.
Read the TC39 Process to better understanding the ECMAScript standards process and what the stages mean.
The example could be rewritten as follows to be ES6/ES2015 compliant.
Using State Correctly
There are three things you should know about setState().
Do Not Modify State Directly
class Clock extends React.Component {state = {time: new Date().toLocaleTimeString(),};refresh = () => {// don't modify state directly// this.state.time = new Date().toLocaleTimeString();//instead call setState, React calls render after setStatethis.setState({ time: new Date().toLocaleTimeString() });};render() {return (<div><p>{this.state.time}</p><button onClick={this.refresh}>Refresh</button></div>);}}ReactDOM.createRoot(document.getElementById("root")).render(<Clock />);State Updates are Merged
setState
could be named please update these parts of state- In the example below, the button label is still Refresh even after clicking the button that causes state to be set (but doesn't set the
buttonLabel
).
class Clock extends React.Component {state = {time: new Date().toLocaleTimeString(),buttonLabel: "Refresh",};refresh = () => {this.setState({ time: new Date().toLocaleTimeString() });};render() {return (<div><p>{this.state.time}</p><button onClick={this.refresh}>{this.state.buttonLabel}</button></div>);}}ReactDOM.createRoot(document.getElementById("root")).render(<Clock />);State Updates May Be Asynchronous
React may batch multiple setState() calls into a single update for performance.
Because
this.props
andthis.state
may be updated asynchronously (after an http request or a user action like clicking a button ), you should not rely on their values for calculating the next state.
For example, this code may fail to update the counter:
// Wrongthis.setState({counter: this.state.counter + this.props.increment,});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:// Correctthis.setState((state, props) => ({counter: state.counter + props.increment,}));We used an arrow function above, but it also works with regular functions:
// Correctthis.setState(function (state, props) {return {counter: state.counter + props.increment,};});
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:
This also works for user-defined components:
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:
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.