Async Nature Of setState()
Gist:
Main Idea
class TestComponent extends React.Component {
constructor(...args) {
super(...args);
this.state = {
dollars: 10
};
this._saveButtonRef = (btn => { this._btnRef = btn });
[
'_onTimeoutHandler',
'_onMouseLeaveHandler',
'_onClickHandler',
'_onAjaxCallback',
].forEach(propToBind => {
this[propToBind] = this[propToBind].bind(this);
});
}
componentDidMount() {
// Add custom event via `addEventListener`
//
// The list of supported React events does include `mouseleave`
// via `onMouseLeave` prop
//
// However, we are not adding the event the `React way` - this will have
// effects on how state mutates
//
// Check the list here - https://reactjs.org/docs/events.html
this._btnRef.addEventListener('mouseleave', this._onMouseLeaveHandler);
// Add JS timeout
//
// Again,outside React `world` - this will also have effects on how state
// mutates
setTimeout(this._onTimeoutHandler, 10000);
// Make AJAX request
fetch('https://api.github.com/users')
.then(this._onAjaxCallback);
}
render() {
console.log('State in render: ' + JSON.stringify(this.state));
return (
<button
ref={this._saveButtonRef}
onClick={this._onClickHandler}>
'Click me'
</button>
);
}
_onClickHandler() {
console.log('State before (_onClickHandler): ' + JSON.stringify(this.state));
this.setState({
dollars: this.state.dollars + 10
});
console.log('State after (_onClickHandler): ' + JSON.stringify(this.state));
}
_onMouseLeaveHandler() {
console.log('State before (mouseleave): ' + JSON.stringify(this.state));
this.setState({
dollars: this.state.dollars + 20
});
console.log('State after (mouseleave): ' + JSON.stringify(this.state));
}
_onTimeoutHandler() {
console.log('State before (timeout): ' + JSON.stringify(this.state));
this.setState({
dollars: this.state.dollars + 30
});
console.log('State after (timeout): ' + JSON.stringify(this.state));
}
_onAjaxCallback(response) {
if (response.status !== 200) {
console.log('Error in AJAX call: ' + response.statusText);
return;
}
console.log('State before (AJAX call): ' + JSON.stringify(this.state));
this.setState({
dollars: this.state.dollars + 40
});
console.log('State after (AJAX call): ' + JSON.stringify(this.state));
}
};
// Render to DOM
ReactDOM.render(
<TestComponent />,
document.getElementById('app')
);Possible solution?
An example might be:
A note on the async nature of setstate
Related links:
Last updated