Is it wrong to modify state in this way?

Tell us what’s happening:
Describe your issue in detail here.
Below I have two version of each return. They both appear to work, but as best as I can tell I am suppose to return the object and not modify state, does that make the version I have remmed out invalid? if so, why?

  **Your code so far**

class Counter extends React.Component {
constructor(props) {
  super(props);
  this.state = {
    count: 0
  };
  // Change code below this line
  this.increment = this.increment.bind(this);
  this.decrement = this.decrement.bind(this);
  this.reset = this.reset.bind(this);
  // Change code above this line
}
// Change code below this line
increment() {
  console.log('increase it')
  this.setState(
    (state) => {
      console.log(state, state.count)
      // return state.count++
      return { count: state.count + 1 }
    }
  )
}
decrement() {
  console.log('decrese it')
  this.setState(
    (state) => {
      console.log(state, state.count)
      // return state.count--
      return { count: state.count - 1 }
    }
  )
}
reset() {
  console.log('reset it')
      this.setState(
    (state) => {
      console.log(state,state.count)
      // return state.count = 0
      return {count: 0}
      }
  )
}
// Change code above this line
render() {
  return (
    <div>
      <button className='inc' onClick={this.increment}>Increment!</button>
      <button className='dec' onClick={this.decrement}>Decrement!</button>
      <button className='reset' onClick={this.reset}>Reset</button>
      <h1>Current Count: {this.state.count}</h1>
    </div>
  );
}
};
  **Your browser information:**

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36

Challenge: Write a Simple Counter

Link to the challenge:

May be this reference might help? https://reactjs.org/docs/react-component.html#setstate.

I might be wrong, but I don’t see anything wrong with those returns, with reference to the documentation, and I believe both return are doing the same thing.

However, for the “not modify state,” might be a different context/issue than issue of what to return. In this code block, I believe the practice of incrementing/decrementing this.state right away is not wrong since the value given is of Primitive type, not of Reference type (e.g. POJO Object, array). For the Reference type we do not modify the state property value, but we need to make a new copy of the previous state property, modify that copy, then return that modified copy as the new state. There’re a few approaches to achieve that, utilizing spread operator, slice method or concat method.

e.g.

class Counter extends React.Component {
constructor(props) {
  super(props);
  this.state = {
    count: [ ]
  };
  // Change code below this line
  this.increment = this.increment.bind(this);
  this.otherincrement = this.otherincrement.bind(this);
  this.decrement = this.decrement.bind(this);
  this.reset = this.reset.bind(this);
  // Change code above this line
}
// Change code below this line
increment() {
  this.setState(
    (state) => {
      const prevCount = [...state.count];
      prevCount.push(newData);
      state.count = prevCount;
      return state;
      // I myself prefer to return the state as a whole, not sure if it's the right way
     // some people just did return; and it seems to work too; 
    }
  )
}
otherincrement() {
  this.setState(
    (state) => {
      state.count = state.count.concat[newData];
      return state;
    }
  )
}
decrement() {
  this.setState(
    (state) => {
      const prevCount = state.count.slice(0);
      prevCount.pop();
      state.count = prevCount;
      return state;
    }
  )
}
reset() {
  console.log('reset it')
      this.setState(
    (state) => {
      console.log(state,state.count)
      // return state.count = [ ]
      return {count: [ ]}
      }
  )
}
// Change code above this line
render() {
  return (
    <div>
      <button className='inc' onClick={this.increment}>Increment!</button>
      <button className='dec' onClick={this.decrement}>Decrement!</button>
      <button className='reset' onClick={this.reset}>Reset</button>
      <h1>Current Count: {this.state.count}</h1>
    </div>
  );
}
};

1 Like

Basically, you want to avoid mutation to avoid bugs. Just because something seems to work doesn’t mean it can’t have bugs (or edge cases). There are some specific reasons in React, but the rule of avoiding mutation isn’t just for React, but a general rule.

reactjs: using state correctly

Dealing with app state is already tricky, the better you can reason about it and gauge it, the better off you are. If you want to use a mutating syntax you can use something like Immer or look at some other immutable libraries.

1 Like

so, are you saying it is better to use the functional return?

I tried to “force” a bug, but i didn’t have many options beyond trying to hit the buttons faster (but I suspect it could process far faster than i could input values and keep track).

The logic makes sense to me, but tbh I have yet to get very far into the weed developing any apps to truly understand what could go wrong. The ‘edge’ case seems very plausible if I were to do anything that called for something outside of my app, like calling another API?

I’m still a baby at learning, but I’ve done the best I can to try to understand things before I keep moving forward, often by trying variations and trying to ‘break’ things, just so I can see what ‘going wrong’ really means.

it may just take me getting into a project to understand this enough.

As a concept, i’m really struggling with what is React and what isn’t. I’m seeing clear indications that I am implementing raw javascript within parts of React, but can’t keep it all in my head enough… yet…

As said, there are specific reasons why mutating state in React is a bad idea and should be avoided. But at this point in your React learning process just knowing the rule and following it is all you really need. You might find yourself going down a bit of a rabbit hole otherwise.

Some random links with examples of bugs in mutating code. May, or may not, be useful.


React can be a little confusing at first, especially if you have done plain DOM manipulation before. But if you stick to it and give it some time it will make more sense and you should end up with an appreciation for the benefits of doing View/State management using such a library/framework.