React code showing how to use setState callback.

To perform an action in a React component after calling setState, such as making an AJAX request or throwing an error, we use the setState callback.

Here’s something extremely important to know about state in React: updating a React component’s state is asynchronous. It does not happen immediately.

Therefore you will run into scenarios whereby parts of your code run before state has had a chance to update.

To solve this specific React issue, we can use the setState function’s callback. Whatever we pass into setState’s second argument executes after the setState function updates.

setState Callback in a Class Component

Let’s see how to perform a callback inside a React class component after setState executes:

setState Callback in Class Component
import React, { Component } from 'react'; class App extends Component { constructor(props) { super(props); this.state = { age: 0, }; } // this.checkAge is passed as the callback to setState updateAge = (value) => { this.setState({ age: value}, this.checkAge); }; checkAge = () => { const { age } = this.state; if (age !== 0 && age >= 21) { // Make API call to /beer } else { // Throw error 404, beer not found } }; render() { const { age } = this.state; return ( <div> <p>Drinking Age Checker</p> <input type="number" value={age} onChange={e => this.updateAge(e.target.value)} /> </div> ); } } export default App;

This nifty drinking age checker component displays a single input. After changing the value inside that input, it changes the age value inside of its state.

Focus in on the checkAge function. That’s where the setState function gets called. Look at the second argument inside that setState function: it’s calling checkAge.

That’s the callback function that will be executed after the age state value is updated.

What we’re essentially doing is waiting until age has fully updated in state to then make the call to check age. If we didn’t wait, we might be checking an older age value.

Cheers! 🍺

setState Callback in a Functional Component

React 16.8 introduced Hooks which gave us a way to add state to functional components through the useState Hook.

However, the useState Hook does not have a second callback argument.

Instead, we use the useEffect Hook and its second argument, which is an array of dependencies.

Let’s take a look at the same example above, but this time in the context of a functional component that uses the useState and useEffect Hooks:

setState Callback in Functional Component
import React, { useEffect, useState } from 'react'; function App() { const [age, setAge] = useState(0); updateAge(value) { setAge(value); }; useEffect(() => { if (age !== 0 && age >= 21) { // Make API call to /beer } else { // Throw error 404, beer not found } }, [age]); return ( <div> <p>Drinking Age Checker</p> <input type="number" value={age} onChange={e => setAge(e.target.value)} /> </div> ); } export default App;

If you haven’t seen Hooks before, why not check out my Simple Introduction to React Hooks.

Much of this component is the same as the Class component, with one vital difference: the useEffect function. Let’s break it down line-by-line:

useEffect(() => { if (age !== 0 && age >= 21) { // Make API call to /beer } else { // Throw error 404, beer not found } }, [age]);

Starting from the bottom, we see parentheses with the age state variable inside of them. This is what’s called the dependency array, and it tells this particular useEffect function to listen out for any changes to the age state variable.

Once the age state variable changes, this useEffect function executes. It’s the equivalent of the setState callback function inside of React class components in our first example.

You can have multiple useEffect functions in a single component.

💻 More React Tutorials
All React Tutorials

📬 The Monthly Upmostly Newsletter

One email a month, packed with the latest React tutorials, delivered straight to your inbox.
Zero spam, just great content. Unsubscribe at any time.

💬 Leave a comment

Your email address will not be published. Required fields are marked *

We will never share your email with anyone else.