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 ...
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.
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.
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.
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.
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 yourprevious
and thecurrentState
since you made the objectmutable
especially in your lifecycle functionsA drawback setting state directly is that React's lifecycle methods -
shouldComponentUpdate()
,componentWillUpdate()
,componentDidUpdate()
- depend on state transitions being called withsetState()
. If you change the state directly and callsetState()
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With