1

I'm studying React JS making a simple todo list and part of my code is as follows:

changeStatus(e, index) {
    this.state.tasks[index].status = e.target.value;
    this.setState((prevState) => ({
        tasks: prevState.tasks
    }));
}

As React documentation says, we shouldn't change state manually, we should call setState instead, so, I'm receiving a warning on console saying that, even calling setState after the manual changing.

I'm doing so because, for me, is more practical doing that than separating the task, doing a splice on my array, and calling setState with the new values.

Is there a problem with my approach? How would you recommend updating state in a efficient and non-repetitive way?

llanfair
  • 1,845
  • 4
  • 27
  • 43
  • 1
    [The React docs outline why this is a bad idea:](https://facebook.github.io/react/docs/react-component.html#state) "Never mutate this.state directly, as **calling setState() afterwards may replace the mutation you made**". In other words, there's no guarantee your changes will actually persist if you mutate the state directly. – Joe Clay Jun 15 '17 at 14:40
  • As I came from Vue, that wasn't a concern for me. Thank you! – llanfair Jun 15 '17 at 14:46
  • Yeah, Vue generally seems to be designed with mutation in mind (which is why a lot of people like it over React, even if that's not my personal preference). The reason you have to use `setState` in React is that it allows for optimizations - e.g. if you call `setState` twice in quick succession, they might be merged into one batch update that's carried out all at once. To quote the docs again: "Think of `setState` as a request rather than an immediate command to update the component." – Joe Clay Jun 15 '17 at 14:50
  • Great. I adopted Vue first because it fits really well for some apps I'm working on. I chose to study React now to use it with React Native Apps and due the market share, although I still prefer Vue. – llanfair Jun 15 '17 at 15:35

2 Answers2

4

Try this :

   changeStatus(e, index) {
      const tmp = { ...this.state };
      tmp.tasks[index].status = e.target.value;
      this.setState(tmp);
   }
Valentin Duboscq
  • 970
  • 8
  • 20
1

You should not mutate the state directly, to do that create a new object from the state and then update that and set it back to state like

changeStatus(e, index) {
    var tasks = {...this.state.tasks}
    tasks[index].status = e.target.value;
    this.setState({tasks});
}

In case you are wondering as to what {...this.state.tasks} do then check this answer:

What is the meaning of this syntax "{...x}" in Reactjs

However you can also make a copy of the state using the ES5 Object.assign() operator like

var tasks = Object.assign({}, this.state.tasks)
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400