React Tips — Async and setState
Tags: webdev, programming, javascript, react
Published: 2021-01-23 19:54:07

**Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62**

**Subscribe to my email list now at http://jauyeung.net/subscribe/**


React is the most used front end library for building modern, interactive front end web apps. It can also be used to build mobile apps.

In this article, we’ll look at the async nature of `setState` and how we should write our code to run multiple `setState` calls sequentially.

### setState’s Asynchronous Nature

The `setState` method is the method to update the component’s internal state. It’s an asynchronous method that’s batched. This means that multiple `setState` calls are batched before a component is rerendered with the new state.

`setState` doesn’t immediately mutate the state but creates a pending state transaction. This means that accessing the `state` immediately after call `setState` can possibly return the old value.

The `setState` method takes up to 2 arguments. We usually pass in only one. The first argument can be an object or a callback that’s used to update the state.

The second argument is a function that’s always run after `setState` is run. For instance, we can pass in a callback in the 2nd argument as follows:

```
import React from "react";
`
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }
`
  update() {
    this.setState(
      ({ count }) => ({
        count: count + 1
      }),
      () => {
        this.setState(({ count }) => ({
          count: count + 2
        }));
      }
    );
  }
`
  render() {
    return (
      <>
        <button onClick={this.update.bind(this)}>Increment</button>
        <p>{this.state.count}</p>
      </>
    );
  }
}
`
export default App;
```

In the code above, we have:

```
update() {
  this.setState(
    ({ count }) => ({
      count: count + 1
    }),
    () => {
      this.setState(({ count }) => ({
        count: count + 2
      }));
    }
  );
}
```

which calls `setState` once, and then calls `setState` again in the callback. This will ensure that one will run after the other.

Therefore, when we click the Increment, the `count` state will increase by 3 every time.

### setState Takes an Object or Function

As we can see from the code above, `setState` can take a callback that returns the new state based on the previous state. This is useful for updating states that are based on the previous state.

In the code above, the new `count` is based on the old `count` , so passing in a callback is more appropriate than passing in an object since we can guarantee that the original state is the lastest when it’s passed in as the callback parameter.

It also takes a `props` parameter as the second parameter which has the props. For instance, we can use it as follows:

```
import React from "react";
`
class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }
`
  update() {
    this.setState(({ count }, { incrementVal }) => ({
      count: incrementVal + count
    }));
  }
`
  render() {
    return (
      <>
        <button onClick={this.update.bind(this)}>Increment</button>
        <p>{this.state.count}</p>
      </>
    );
  }
}
`
export default function App() {
  return <Counter incrementVal={5} />;
}
```

In the code above, we have the `Counter` component, which has the `update` method as we have in the previous example. But this ti,e, the `setState` method takes a callback which has a second parameter. It has the props object.

We can get the prop property values as we did above via the destructuring assignment syntax. Also, we can access the prop object’s property like any other JavaScript object property with the dot or bracket notation.

Therefore, since we have:

```
<Counter incrementVal={5} />
```

in `App` , when we click the Increment button, the `count` state in `Counter` will update by 5 since that’s what we specified.

The most common entity that we pass into `setState` is probably an object. We just pass in an object that has state properties that we want to change. The ones that aren’t included will stay the same.

For instance, if we write:

```
import React from "react";
`
class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0, foo: "foo" };
  }
`
  update() {
    this.setState({ count: this.state.count + 1 });
  }
`
  render() {
    return (
      <>
        <button onClick={this.update.bind(this)}>Increment</button>
        <p>{this.state.count}</p>
        <p>{this.state.foo}</p>
      </>
    );
  }
}
`
export default function App() {
  return <Counter />;
}
```

Then `this.state.foo` has the value `'foo'` even after `this.setstate` in `update` is run.

Therefore, when we click the Increment button, we see ‘foo’ displayed no matter how many times we click it.

### Conclusion

`setState` calls may not be always sequential. The batching sometimes may not be controlled by React. Therefore, if we want to make sure that multiple `setState` calls run sequentially all the time, we should run the second `setState` in the callback that’s passed in as the 2nd argument of `setState` .

Also, `setState` can take an object or a function with the previous state and the props objects as the 1st and 2nd parameters respectively.