Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
June 13, 2020 08:44 pm GMT

3 Mistakes to avoid when updating React state

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.

Case 1: 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.

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>    );  }}

Here is the output -
Check the console.

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

Well the reason is that the calls to setState are asynchronous.

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.

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 - componentDidUpdate() .
  • You can also achieve this using the updater function in setState. This has been discussed in Case-3.

Case 2: 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.

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>    );  }}

Now let's see the output -

So when you are entering the first name, the last name is undefined and vice-versa.
This is happening due to something called shallow merge.
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.
  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.

Case 3: 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

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>    );  }}

Here is the outut -

In this case, the multiple update calls are being batched together and therefore the last call is overriding the previous calls.

How to avoid -

  • Using updater function in setState() - One of the arguments which setState accepts is an updater function.
  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.
  • This is my first blog ever and I would gladly welcome any suggestions and feedback .

Original Link: https://dev.to/anantbahuguna/3-mistakes-to-avoid-when-updating-react-state-45gp

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To