Mills
Mills

Reputation: 57

why is my this.setState not updating the array

am I missing something? I'm using es6 style to add to an empty array in this.state, but nothing is getting pushed to state.

I should be getting two inside of the array, but after console.logging nothing is showing. and my screen is not rerendering, since coponentDidUpdate is not running.

class HomeModal extends Component {
  constructor(props) {
    super(props);
    this.state = {
      specificList: []
    };
    this.updateState = this.updateState.bind(this);
  }

  componentWillMount() {
    this.updateState();
  }

  componentDidUpdate() {
    console.log("after update: ", this.state.specificList);
  }

  updateState = () => {
    this.props.completeList.forEach(index => {
      index.list.forEach(innerArr => {
        if (innerArr.muscleGroup === this.props.selectedBodyPart) {
          console.log("test: ", innerArr);
          this.setState({
            specificList: [...this.state.specificList, innerArr.title]
          });
        }
      });
      console.log("after each loop: ", this.state.specificList);
    });
  };

// console.log results
06:22:48: test:  Object {
06:22:48:   "muscleGroup": "Chest",
06:22:48:   "title": "Barbell Bench Press",
06:22:48: }
06:22:48: after each loop:  Array []
06:22:48: test:  Object {
06:22:48:   "muscleGroup": "Chest",
06:22:48:   "title": "Barbell Bench Press",
06:22:48: }
06:22:48: after each loop:  Array []
06:22:48: after each loop:  Array []

6:08:04: Object { // what innerArr the object looks like
06:08:04:   "muscleGroup": "Chest",
06:08:04:   "title": "Barbell Bench Press",
06:08:04: }

Upvotes: 0

Views: 97

Answers (4)

Pranita
Pranita

Reputation: 339

It would be best to call setState once you have looped through both of you loops. For eg. you can do something like this:

updateState = () => {
  let temp = this.state.specificList;

  this.props.completeList.forEach(index => {
    index.list.forEach(innerArr => {
      if (innerArr.muscleGroup === this.props.selectedBodyPart) {
        console.log("test: ", innerArr);
        temp.push(innerArr.title);
      }
    });
    console.log("after each loop: ", temp)
  });

  this.setState({ specificList: temp }); 
}

Upvotes: 0

JLRishe
JLRishe

Reputation: 101662

setState is asynchronous. That means that the value of the state values don't update immediately.

What you are doing is looping through a series of values and setting the state of specificList to the concatenation of the current value of specificList plus a single item from the array.

So if specificList were ['a', 'b', 'c'] and the array you're looping over were [1, 2, 3], then you would essentially be calling:

setState({ specificList: ['a', 'b', 'c', 1] })
setState({ specificList: ['a', 'b', 'c', 2] })
setState({ specificList: ['a', 'b', 'c', 3] })

You can see how all of the values of the array except for the last one get left out.

One way to fix this is to pass a function to setState instead of a value. This will allow you to work with setState's asynchronous behavior:

updateState = () => {
    this.props.completeList.forEach(index => {
        index.list.forEach(innerArr => {
            if (innerArr.muscleGroup === this.props.selectedBodyPart) {
                console.log("test: ", innerArr);
                this.setState(({ specificList } => ({
                  specificList: [...specificList, innerArr.title]
                }));
            }
        });
      });
};

Upvotes: 0

Blue
Blue

Reputation: 22911

Some small notes on .setState() from the docs:

React may batch multiple setState() calls into a single update for performance.

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

I would simply use another object at the start of the loop (Copying from the current state), modify that variable in the loop, and then do one .setState() at the very end, after all your loops are done.

Upvotes: 2

Tareq El-Masri
Tareq El-Masri

Reputation: 2573

Try to log the output with setState callback, like this:

this.setState({
    specificList: [...this.state.specificList, innerArr.title]
}, () => {
    console.log("after each loop: ", this.state.specificList);
});

Upvotes: 1

Related Questions