简体   繁体   中英

ReactJS - setState working in a weird way

I am trying to add things to a list, in the form of a state array. However, with my current code, the first item doesn't add itself properly.

export default class Main extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      list: [],
      total: 0.00,
      ...
    }
  }

  //some unimportant code here

  addToList = item => {
    this.setState({list: [...this.state.list, item]});

    //This method call for a method that gets the total price of all the items
    this.getTotal(); 
  }

  //this method works fine, except with the first element
  getTotal() {
    this.setState(({sum= 0.0, items, list}) => {
      items.forEach(element => {
        if(this.state.list.length !== 0.0) {
          if(this.state.list.includes(element.name)) {
            sum += parseFloat(element.price);
          }
        }
      });
      this.setState({total: sum});
    });
  }
}

When I console.log the list state I get an empty array for the first item, and then the items are delayed by one. So if I add the item A and look at the console, I see nothing. When I add item B and look at the console, I see an Array with the item A . Any ideas as to what is causing this?

Every access to this.state.list should be replaced with list . this.state.list accesses potentially old state. The whole point of passing a callback is that you can access the current state passed as argument. You are doing this correctly for items , but not for list .

You should also return {total: sum} from the setState callback instead of calling this.setState :

  getTotal() {
    this.setState(({items, list}) => {
      const sum = 0;
      items.forEach(element => {
        if(list.includes(element.name)) {
          sum += parseFloat(element.price);
        }
      });
      return {total: sum};
    });
  }

For the same reason you should use a callback function in addToList :

 addToList = item => {
   this.setState(({list}) => ({list: [...list, item]}));
   this.getTotal(); 
 }

Remember that setState is asyncronous , so if you wanna check the list updated, you have add a callback to the setState :

 addToList = item => {
    this.setState( {list: [...this.state.list, item]}, () =>{ 
     // So if you make anything here, you are sure that the state was updated successfully 
    console.log( this.state.list );
    this.getTotal();
    } );
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM