Reputation: 3686
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 ...
Upvotes: 5
Views: 1344
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 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>
Upvotes: 4