Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
64
rated 0 times [  70] [ 6]  / answers: 1 / hits: 69979  / 8 Years ago, fri, june 10, 2016, 12:00:00

I understand that React tutorials and documentation warn in no uncertain terms that state should not be directly mutated and that everything should go through setState.


I would like to understand why, exactly, I can't just directly change state and then (in the same function) call this.setState({}) just to trigger the render.


E.g.: The below code seems to work just fine:


const React = require('react');

const App = React.createClass({
getInitialState: function() {
return {
some: {
rather: {
deeply: {
embedded: {
stuff: 1,
},
},
},
},
},
};
updateCounter: function () {
this.state.some.rather.deeply.embedded.stuff++;
this.setState({}); // just to trigger the render ...
},
render: function() {
return (
<div>
Counter value: {this.state.some.rather.deeply.embedded.stuff}
<br></br>
<button onClick={this.updateCounter}>Increment</button>
</div>
);
},
});

export default App;

I am all for following conventions but I would like to enhance my further understanding of how ReactJS actually works and what can go wrong or is it sub-optimal with the above code.


The notes under the this.setState documentation basically identify two gotchas:



  1. That if you mutate state directly and then subsequently call this.setState this may replace (overwrite?) the mutation you made. I don't see how this can happen in the above code.

  2. That setState may mutate this.state effectively in an asynchronous / deferred way and so when accessing this.state right after calling this.setState you are not guaranteed to access the final mutated state. I get that, by this is not an issue if this.setState is the last call of the update function.


More From » reactjs

 Answers
20

The React docs for setState have this to say:




NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.



setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.



There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.



setState() will always trigger a re-render unless conditional rendering logic is implemented in shouldComponentUpdate(). If mutable objects are being used and the logic cannot be implemented in shouldComponentUpdate(), calling setState() only when the new state differs from the previous state will avoid unnecessary re-renders.




Basically, if you modify this.state directly, you create a situation where those modifications might get overwritten.



Related to your extended questions 1) and 2), setState() is not immediate. It queues a state transition based on what it thinks is going on which may not include the direct changes to this.state. Since it's queued rather than applied immediately, it's entirely possible that something is modified in between such that your direct changes get overwritten.



If nothing else, you might be better off just considering that not directly modifying this.state can be seen as good practice. 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.


[#61813] Wednesday, June 8, 2016, 8 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
jocelynkarsynr

Total Points: 472
Total Questions: 98
Total Answers: 96

Location: Macau
Member since Mon, Nov 16, 2020
4 Years ago
jocelynkarsynr questions
Tue, Feb 8, 22, 00:00, 2 Years ago
Sat, Jul 11, 20, 00:00, 4 Years ago
Sun, May 10, 20, 00:00, 4 Years ago
Sat, Jan 18, 20, 00:00, 4 Years ago
;