7

I have problem doing a setState changing value of a nested array of object. Below code suppose to change question of id 2 to answer: true but it did not, what's wrong?

this.state = {
  questions: [
    {
      id: 1,
      answer: ''
    },
    {
      id: 2,
      answer: ''
    },
  ]
}
//I have a click event somewhere
this.setState(
  {
    questions: this.state.questions.map(q => {
      if (q.id === 2) {
        return {
          ...q,
          answer: true
        }
      } else {
        return { ...q }
      }
    })
  },
  console.log(this.state.questions[1]) // did not see id of 2 being changed to true?
)
2
  • @Finesse it's the state, updated Commented Sep 21, 2018 at 0:53
  • Actually, OP updates the state correctly. Commented Sep 21, 2018 at 1:01

3 Answers 3

4

The console.log(this.state.questions[1]) line is executed before the this.setState line is executed, that's why the old state is printed to the console. You should put the line inside a function to delay the execution:

this.setState(..., () => console.log(this.state.questions[1]));

Also it is recommended to use a function as the first argument if the changed state is derived from the current state because React doesn't apply the new state immediately therefore this.state can be outdated when React applies the new state:

this.setState(state => ({
  questions: state.questions.map(q => {
    if (q.id === 2) {
      return {...q, answer: true};
    }
    return q;
  })
}), () => {
  console.log(this.state.questions[1]);
});
Sign up to request clarification or add additional context in comments.

1 Comment

Err, probably a missing part here :) questions.map should be state.questions.map. Right? :)
0

You are not invoking your setState callback. Try like this:

this.setState(
  {
    questions: this.state.questions.map(q => {
      if (q.id === 2) {
        return {
          ...q,
          answer: true
        };
      }
      return { ...q };
    })
  },
  () => console.log(this.state.questions[1]) // did not see id of 2 being changed to true?
);

Though, since you are using the current state to update your state again, it would be better to use functional setState.

this.setState(
  currentState => ({
    questions: currentState.questions.map(q => {
      if (q.id === 2) {
        return {
          ...q,
          answer: true
        };
      }
      return { ...q };
    })
  }),
  () => console.log(this.state.questions[1])
);

Also, you don't have to log your state in a callback to setState. You can log your state in your render method without struggling setState's callback.

this.setState(
  currentState => ({
    questions: currentState.questions.map(q => {
      if (q.id === 2) {
        return {
          ...q,
          answer: true
        };
      }
      return { ...q };
    })
  })
);

....

render() {
    console.log( this.state );
    ....
}

Comments

-1

I think it's because Array.map returns an array. Try:

this.setState(
  {
    questions: this.state.questions.map(q => {
      if (q.id === 2) {
        q.answer = true;
      } 
      return q;
    })
  },
  console.log(this.state.questions[1]) // did not see id of 2 being changed to true?
)

3 Comments

Hi @Charlie. As a crucial suggestion, do not mutate your state, your object properties like that using React, Redux, etc. Never. OP is doing right.
yeah you're right: immutability in objects, that's Redux's principle
Also, in React's state :) Good luck on your developing journey.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.