Dominik Serafin
Dominik Serafin

Reputation: 3686

Disadvantages mutating state directly and forceUpdate() vs setState

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:

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 ...

Upvotes: 5

Views: 1344

Answers (1)

Shubham Khatri
Shubham Khatri

Reputation: 281646

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>

Upvotes: 4

Related Questions