Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disadvantages mutating state directly and forceUpdate() vs setState

Tags:

React docs say Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable... But this is a non issue when I don't use setState() at all.

The only disadvantages I can think of are:

  • Can't use shouldComponentUpdate/componentWillUpdate/componentDidUpdate to compare old and new state.

  • Will probably make maintainability harder for others working on it. Since it's not the standard way to do things.

But are there any other disadvantages to not using setState() and mutating state directly?


EDIT: I've deleted my reasoning why I'm attracted to that idea. I know it's an anti-pattern and I know it's probably not the best way to do it. But this question is all about "why".

EDIT2: Also key word here is other in ... are there any other disadvantages ...

like image 497
Dominik Serafin Avatar asked Nov 11 '17 11:11

Dominik Serafin


People also ask

Why should we not mutate States directly in React?

If we were to mutate state directly, not only would we lose this functionality, but since there is no reference point, adding to or changing the value of an existing element is still going to equal it's previous state.

What is the problem with updating state directly instead of setState ()?

If you update it directly, calling the setState() afterward may just replace the update you made. When you directly update the state, it does not change this. state immediately. Instead, it creates a pending state transition, and accessing it after calling this method will only return the present value.

What is the difference between setState () and forceUpdate ()?

The difference between forceUpdate() and setState() is te setState() re-render the component if some state or props of that component is changed. When we call setState() the lifecycle method shouldComponentUpdate() method calls automatically that decide if the component should re-render or not.

What is the best method to update state in component?

setState method allows to change of the state of the component directly using JavaScript object where keys are the name of the state and values are the updated value of that state. Often we update the state of the component based on its previous state.


1 Answers

You should not directly mutate the state. Async nature of setState has ways to get around it. setState provides a callback that you can use.

Also forceUpdate completely bypasses the shouldComponentUpdate which is not a good pattern especially when using React.PureComponent that does a shallow comparison of your props.

Also you should not use anti patterns, rather try to solve your issues the correct way suggested by the docs

The other advantage of using setState that you may loose with this pattern is to compare your previous and the currentState since you made the object mutable especially in your lifecycle functions

A drawback setting state directly is that React's lifecycle methods - shouldComponentUpdate(), componentWillUpdate(), componentDidUpdate() - depend on state transitions being called with setState(). If you change the state directly and call setState() with an empty object, you can no longer implement those methods.

Also You may know personally that your code interacts with React in such a way that these over-writes or other issues can't happen but you're creating a situation where other developers or future updates can suddenly find themselves with weird or subtle issues when they start following the right approach

Using setState to mutate state

class App extends React.Component {
  state =  {
      counter: 0
  }
  updateCounter = () => {
    this.setState(prevState => ({counter: prevState.counter + 1}));
  }
  componentWillUpdate(nextProps, nextState){
    console.log(this.state.counter === nextState.counter);
  }
  
  componentDidUpdate(prevProps, prevState) {
     console.log(this.state.counter === prevState.counter);
  }
  render() {
      return (
        <div>
          {this.state.counter}
          <button onClick={this.updateCounter}>Increment</button>
        </div>
      )
  }
}

ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

Directly mutating state

class App extends React.Component {
  state =  {
      counter: 0
  }
  updateCounter = () => {
    this.state.counter =  this.state.counter + 1;
    this.forceUpdate();
  }
  componentWillUpdate(nextProps, nextState){
    console.log(this.state.counter === nextState.counter);
  }
  
  componentDidUpdate(prevProps, prevState) {
     console.log(this.state.counter === prevState.counter);
  }
  render() {
      return (
        <div>
          {this.state.counter}
          <button onClick={this.updateCounter}>Increment</button>
        </div>
      )
  }
}

ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
like image 172
Shubham Khatri Avatar answered Sep 30 '22 16:09

Shubham Khatri