The setState Callback in React

Irakli Tchigladze Oct 22, 2021
  1. Why Is the Callback Argument Necessary?
  2. When to Use setState() Callback?
The setState Callback in React

At first glance, React components’ .setState() method seems simple enough. It updates the existing state to reflect the changes in the argument. However, many people don’t know that the .setState() method also accepts another optional argument. This argument is a callback function, which is executed right after the state is updated.

In order to write more reliable code, you need to understand what the .setState() callback function does and how you can use it.

Why Is the Callback Argument Necessary?

Most React developers don’t know that .setState() method is asynchronous. The update doesn’t happen immediately. If you try to read the updated contents of state right after a setState() call, you might be unsuccessful or read the wrong data.

To resolve this problem, the setState() method takes another optional argument - a callback function. The actions specified in the callback function will be performed only after the state is updated.

When to Use setState() Callback?

As we mentioned above, the setState call is asynchronous. It doesn’t update the state object immediately. If you want to perform a check or some other action based on the most recent update, using the setState() callback is a good practice. However, it’s not the only way to perform such operations. We discuss the alternatives in later sections.

The setState() callback is useful for these types of actions: making calls to the API, checking the content of state to conditionally throw an error, and other operations that need to be performed right after the state is updated. setState() callback is also frequently used for validation.

For instance, if we want to use the <input> to update the state, we can use the callback function to read the updated value with absolute certainty. Without a callback, we could be checking the stale, older versions of the state.

Code example:

class App extends Component {
  constructor(props){
    super(props)
    this.state = {
      text: ""
    }
  }
  render() {
    return (
    <div>
    	<h1>Hello World</h1>
   		<input type="text" 
         onChange={(e) => this.setState({text: e.target.value}, 
         () => console.log(this.state.text))}></input>
    </div>
    )
  }
}

Callback Function vs render()

Skeptics might ask why I need setState() callback when I can access the updated state in the body of the render() method?

The difference is, render() method will run every time the state is updated, whereas a setState() callback will only run after updating the specific value in the state.

.setState() in an async Function

Sometimes .setState() method can be called in asynchronous functions. In this case, the state will not be updated immediately.

If you read the value of the state property using the this keyword, you’re going to get an old value. On the other hand, the callback function is called once the async task is done.

Alternative

React documents recommend that developers use the componentDidUpdate() lifecycle method instead, only available for class components.

For functional components, useEffect() can effectively replace all lifecycle hooks, including componentDidUpdate(). You only have to customize the dependency array.

For instance, if your state has an age property, and you want to check its value once the state is updated, useEffect() hook would look like this:

useEffect(()=>console.log(`doing something with ${this.state.age}`), [age])
Irakli Tchigladze avatar Irakli Tchigladze avatar

Irakli is a writer who loves computers and helping people solve their technical problems. He lives in Georgia and enjoys spending time with animals.

LinkedIn