Using a function in `setState` instead of an object
2/6/2018 Update: While this article was written over a year ago (and React 16 has been released!), the code and principles in it still apply.
The React documentation has recently been revamped — if you haven’t checked it out yet, you should! I have been helping out a little bit with the documentation by writing up a “Glossary of React Terms” and in that process I’ve been thoroughly reading all the new documentation. In reading the documentation I found out about a relatively unknown aspect of `setState` and inspired by this tweet:
I thought I’d write a blog post explaining how it works.
First, a little background
Components in React are independent and reusable pieces of code that often contain their own state. They return React elements that make up the UI of an application. Components that contain local state have a property called state
When we want to change our how application looks or behaves, we need to change our component’s state. So, how do we update the state of our component? React components have a method available to them called setState
Calling this.setState
causes React to re-render your application and update the DOM.
Normally, when we want to update our component we just call setState
with a new value by passing in an object to the setState
function: this.setState({someField:someValue})
But, often there is a need to update our component’s state using the current state of the component. Directly accessing this.state
to update our component is not a reliable way to update our component’s next state. From the React documentation:
Because
this.props
andthis.state
may be updated asynchronously, you should not rely on their values for calculating the next state.
The key word from that documentation is asynchronously. Updates to the DOM don’t happen immediately when this.setState
is called. React batches updates so elements are re-rendered to the DOM efficiently.
An example
Let’s look at a typical example of how to use setState
In Shopsifter, I have a feedback form which, after the user submits his/her feedback, shows a thank you message like so:
The component for the feedback page has a showForm
boolean which determines whether the form or the thank you message should display. The initial state of my feedback form component looks like this:
this.state = { showForm : true}
Then, when the user clicks the submit button, I call this function:
submit(){
this.setState({showForm : !this.state.showForm});
}
I am relying on the value of this.state.showForm
to modify the next state of my form. In this simple example, we probably would not run into any issues by relying on this value, but you might imagine that as an application gets more complex and there are multiple setState
calls happening and queuing up data to be rendered to the DOM, there is a possibility that the actual value of this.state.showForm
might not be what you think.
If we shouldn’t rely on this.state
to calculate the next value, how do we calculate the next value?
Function in `setState` to the rescue!
Instead of passing in an object to this.setState
we can pass in a function and reliably get the value of the current state of our component. My submit function from above now looks like this:
submit(){
this.setState(function(prevState, props){
return {showForm: !prevState.showForm}
});}
Passing in a function into setState
instead of an object will give you a reliable value for your component’s state
and props
. One thing to note is that the React documentation makes use of arrow functions in their examples (which is also on my list of things to migrate to in my Shopsifter app!) so in my example above I’m using ES5 syntax for my function.
If you know you’re going to use setState
to update your component and you know you’re going to need the current state or the current props of your component to calculate the next state, passing in a function as the first parameter of this.setState
instead of an object is the recommended solution.
I hope this helps you make better, more reliable React applications!
-Sophia