Editor’s note: This post was last updated on 30 July 2021. It may still contain information that is out of date.
States in React, like props, are objects that store data and affect how a component renders or behaves. Unlike props, states are managed completely within the component and can be changed over time.
User actions, network activity, API requests, or specific application behaviors can often trigger changes in state for React components.
In this article, we’ll review:
setState()
in React?setState()
in React lifecycle methodsComponents that have a state are referred to as stateful components, while those that do not have states are stateless components.
A component can have an initial state set, access it, and update it. In the code block below, we are setting the component’s initial state. This is done through the constructor method:
import React, { Component } from 'react'; class Food extends Component { constructor(props) { super(props) this.state = { fruits: ['apple', 'orange'], count: 0 } } }
Because states are plain JavaScript objects, this.state
must be equal to an object:
this.state = { fruits: ['apple', 'orange'], count: 0 }
Avoid confusing the state
object with other instance properties. It’s easy to assume you can define another object in the constructor and try to use it like state
, but the state
instance is a special one because React manages it:
... //constructor function above this.state = { fruits: ['apple', 'orange'], count: 0 } this.user = { name: 'Obaseki Nosa' } ...
Although both this.state
and this.user
are objects initialized in the constructor, only this.state
reacts with setState()
and is managed by React.
We can access component states like other object using this.state.property_name
.
To access the count
in the above example, we;ll use this.state.count
:
render() { return ( <div className = "container"> <h2> Hello!!!</h2> <p> I have {this.state.count} fruit(s)</p> </div> ); }
Although it is technically possible to write to this.state
from anywhere in your code, it does not prompt a rerender, which would lead to unstable and incorrect state values when trying to access values through this.state
.
The only place you should directly write to this.state
is the component’s constructor method.
Use the setState()
method everywhere else; doing so accepts an object that eventually merges into the component’s existing state.
For example, the following does not rerender a component:
// Wrong this.state.name = 'Obaseki Nosa';
Instead, use setState()
.
setState()
in React?The setState()
schedule changes to the component’s state object and tells React that the component and its children must rerender with the updated state:
// Correct this.setState({name: 'Obaseki Nosa'});
React intentionally waits until all components call setState()
in their event handlers before rerendering. This boosts performance by avoiding unnecessary rerenders.
setState()
can be considered as a request instead of an immediate command to update the component. This is why trying to use this.state
immediately after a setState()
leads to incorrect behaviors:
// Trying to change the value of this.state.count from previous example this.setState({ count: 4 }); console.log(this.state.count); // 0
this.state.count
returns 0
because even though the value is set with setState()
, it was only scheduled and not rerendered before attempting to use the value with this.state
.
setState()
always leads to a rerender unless shouldComponentUpdate()
returns false
.
setState()
in React lifecycle methodsCalling setState()
in React’s lifecycle methods requires a certain level of caution. There are a few methods where calling setState()
leads to undesirable results and others to avoid completely. Let’s look at a few methods and how they react when calling setState()
render()
Calling setState()
here makes it possible for a component to produce infinite loops.
The render()
function should be pure, meaning that it does not modify a component’s state. It returns the same result each time it’s invoked, and it does not directly interact with the browser.
In this case, avoid using setState()
here.
constructor()
Do not call setState()
in constructor()
. Instead, if a component needs to use a local state, assign the initial state to this.state
directly in the constructor.
componentDidMount()
componentDidMount()
invokes immediately after a component mounts. You can call setState()
immediately in componentDidMount()
and triggers an extra rendering, but this happens before the browser updates the screen, calling render()
twice.
componentDidUpdate()
componentDidUpdate()
invokes immediately after updating. You can call setState()
immediately here, but it must be wrapped in a condition like in the example below, or it causes an infinite loop:
componentDidUpdate(prevProps, prevState) { let newName = 'Obaseki Nosa' // Don't forget to compare states if (prevState && prevState.name !== newName) { this.setState({name: newName}); } }
componentWillUnmount()
Do not call setState()
here because the component does not rerender. Once a component instance unmounts, it never mounts again.
This concludes our overview of setState()
. Some things to remember when using setState()
include:
setState()
is async, meaning there is no guarantee that the state has updated when trying to access the value immediatelystate
with setState
and React will react to the changeCheers!!!
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowMicro-frontends let you split a large web application into smaller, manageable pieces. It’s an approach inspired by the microservice architecture […]
Nitro.js is a solution in the server-side JavaScript landscape that offers features like universal deployment, auto-imports, and file-based routing.
Ding! You got a notification, but does it cause a little bump of dopamine or a slow drag of cortisol? […]
A guide for using JWT authentication to prevent basic security issues while understanding the shortcomings of JWTs.