3 Mistakes to avoid when updating React state
Tags: javascript, react, setstate
Published: 2020-06-13 20:44:42

---
title: 3 Mistakes to avoid when updating React state
published: true
description: How to update React state the right way
tags: javascript, react, setState
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/zly3mae6na3h7l7306y4.jpg
---


Today, I am going to share with you 3 scenarios we may encounter while updating react `states`. I have often seen these common mistakes being made by some beginner React devs. I'll also show you how to avoid those mistakes.
So let's get started.
<br/>
### <b>Case 1:</b>  Reading state just after `setState()`
Have you ever tried checking the state just after `setState()`. If you haven't, let me get my hands dirty for you.

Here we have a count state which can be incremented using a button.

``` javascript
export default class App extends Component {
  state = {
    count: 0
  }
  handleClick = () => {
    this.setState({
      count: this.state.count+1
    })
    console.log(this.state.count)
  }
  render() {
    return (
      <div className="App">
        <h1>{this.state.count}</h1>
        <button onClick={this.handleClick}>+</button>
      </div>
    );
  }
}
```
<br/>
Here is the output - 
<sub>Check the console.</sub>
<br/>
![Output](https://dev-to-uploads.s3.amazonaws.com/i/x8uavswkn4lalgbf6r37.gif)
<br/>

So why aren't we getting the updated state in console ?

Well the reason is that the calls to `setState` are asynchronous.<br/>

So by calling setState(), we are making a request to update the state and meanwhile moving to the next line. Then the state is logged in console before the update request is completed. <br/>
> Therefore, it isn't recommended to access `this.state` right after calling setState().

### How to avoid -
- If you want to access the state just after setState, you may do so inside the lifecycle method - <b>componentDidUpdate()</b> or <b>useEffect</b> for functional components .
- You can also achieve this using a callback function inside the setState function. Do note that this methd won't work for setter function of useState hook. 
<figcaption>
Thanks to <b>Geordy James</b> for reminding this method.
</figcaption>

---

### <b>Case 2:</b>  Updating `object` or `array` states the wrong way
Let's try to update an object state. 
The following code is taking input of first name and last name and updating the states of fistName and lastName using two respective functions, but something strange is happening.
```javascript

export default class App extends Component {
  state = {
    name: {
      firstName: "",
      lastName: ""
    }
  };
  addFirstName = e => {
    this.setState({
      name: {
        firstName: e.target.value
      }
    });
  };
  addLastName = e => {
    this.setState({
      name: {
        lastName: e.target.value
      }
    });
  };
  resetName = () => {
    this.setState({
      name: {
        firstName: "",
        lastName: ""
      }
    });
  };
  render() {
    return (
      <div className="App">
        First Name:
        <input value={this.state.name.firstName} onChange= 
        {this.addFirstName} />
        <br />
        <br />
        Last Name:
        <input value={this.state.name.lastName} onChange= 
        {this.addLastName} />
        <br />
        <br />
        <button onClick={this.resetName}>Reset</button>
        <h1>{`Your name is ${this.state.name.firstName} ${
        this.state.name.lastName}`}</h1>
      </div>
    );
  }
}


```

<br/>
Now let's see the output - 
<br/>
![output](https://dev-to-uploads.s3.amazonaws.com/i/ju7be18d3fw2z1nae0hh.gif)
<br/>

So when you are entering the first name, the last name is undefined and vice-versa.
This is happening due to something called <b>shallow merge</b>. 
When you update state by passing an object inside setState(), the state is updated by shallow merging. Shallow merging is a concept in javascript,using which if two objects are merged, the properties with same keys are overwritten by value of the same keys of second object.

So in our case, when we are updating first name, setState is overwriting the complete name object with the new object passed in the setState, which has either firstName or lastName.

### How to Avoid - 

- Use spread operator(...) - 
  Just use spread operator to make a copy of the state and then 
  update the state.
  ```javascript
  addFirstName = e => {
    this.setState({
      name: {
      ...this.state.name,
        firstName: e.target.value
      }
    });
  };
  addLastName = e => {
    this.setState({
      name: {
      ...this.state.name,
        lastName: e.target.value
      }
    });
  };
  ```
#### Note - This case also applies to `array` states.
---

### <b>Case 3:</b>  Updating state multiple times consecutively

Imagine we want to update the state multiple times in a row. We may try in the following manner. 
Here we are incrementing count by 10 
 
``` javascript
import React, { Component } from "react";
import "./styles.css";

export default class App extends Component {
  state = {
    count: 0
  };
  handleClick = () => {
    for (let i = 0; i < 10; i++) {
      this.setState({
        count: this.state.count + 1
      });
    }
  };
  render() {
    return (
      <div className="App">
        <h1>{this.state.count}</h1>
        <button onClick={this.handleClick}>Add 10</button>
        <button onClick={() => this.setState({ count: 0 })}>Reset</button>
      </div>
    );
  }
}


```

<br/>
Here is the output - 
<br/>
![output](https://dev-to-uploads.s3.amazonaws.com/i/he8ggkvoraqabeshl0r1.gif)
<br/>

So, instead of incrementing by 10, it is only incrementing by 1.

Well, here is the reason.
In this case, the multiple update calls are being batched together. Therefore the last call is overriding the previous calls and count is only incremented by 1.


### How to avoid - 

- Using updater function in setState() - 
  One of the arguments which setState accepts is an updater function.
  ```javascript
  handleClick = () => {
    for(let i = 0;i<10;i++) {
      this.setState((prevState) => {
        return {
            count: prevState.count + 1
        }
      })
    }
  };
  ```
This way all our updates are chained and updation occurs consecutively just as we wanted, instead of calls overriding each other.

> So whenever your new state value depends on the current state value, use the updater function which will always give you the current updated state.

---

### Closing Note -
- All these cases remain same for `useState()` hook since the setter function of useState hook is `setState()` only.
- Currently, setState calls are only batched inside event handlers but in the upcoming `React v17`, this will be the default behaviour.
- If you want to know more about why setState is Asynchronous or why calls to setState are batched, read this in-depth [comment](https://github.com/facebook/react/issues/11527#issuecomment-360199710).
- This is my first blog ever and I would gladly welcome any suggestions and feedback 🤗.