setState
has a form that accepts a callback updater
. This updater
is invoked when this state transition actually occurs (since setState
may be asynchronous), accepting state
and props
of the component as explicit arguments at the time of state setting. Is there any difference to referring to these arguments vs. this.state
and this.props
? The docs say:
That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument.
My motivation to know is that I have some pure functions of props and state in this component to calculate some derived values that are sometimes fed back into state. I'd like to avoid rewriting these functions when they're needed in setState
.
One big difference is that this.state
will only update after all currently queued setState
calls have finished:
class Component extends React.Component {
constructor() {
super();
this.state = { count: 0 };
}
increment() {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<div>{this.state.count}</div>
<button onClick={() => { this.increment(); this.increment(); }}>
+
</button>
</div>
);
}
}
ReactDOM.render(
<Component />,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
If the this.state
updated immediately, you'd see the count jump from 0 to 2 to 4, etc, but it doesn't; it updates one-by-one, because this.state
doesn't update immediately.
In contrast, using the callback form's argument does provide you with the possibly-just-updated value.
class Component extends React.Component {
constructor() {
super();
this.state = { count: 0 };
}
increment() {
this.setState(({ count }) => ({ count: count + 1 }));
};
render() {
return (
<div>
<div>{this.state.count}</div>
<button onClick={() => { this.increment(); this.increment(); }}>
+
</button>
</div>
);
}
}
ReactDOM.render(
<Component />,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>