I have been coding my ReactJS AJAX requests like this:
this.setState({
isLoading: true,
results: null
});
$.get(ajaxUrl, function(results) {
this.setState({
isLoading: false,
results: results
});
}.bind(this));
This is just an example, it lacks error handling, throttling, cancelling requests, etc. But the gist is there. I basically ask for some state to be set and then issue a request.
Looking at some other code on GitHub, though, I noticed that some people write their AJAX calls in the setState callback:
this.setState({
isLoading: true,
results: null
}, function() {
$.get(ajaxUrl, function(results) {
this.setState({
isLoading: false,
results: results
});
}.bind(this));
}.bind(this));
Is there a valid reason to do so? The docs say:
There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.
So there is no guarantee that setState mutates the state before returning, but I see no mention that different setState's may execute out of order. So the worst that could happen is that the "loading" state never gets rendered. Is this what the latter style is trying to solve? Is there some other risk I fail to see?
but I see no mention that different setState's may execute out of order
Correct they are run in order, and from a UX perspective you don't want to show a loading indicator for less than half a second.
The case for needing this looks more like this:
this.setState({
isLoading: true,
results: this.state.results || []
}, function() {
$.get(ajaxUrl, function(results) {
this.setState({
isLoading: false,
// note! we're referring to state here
results: this.state.results.concat(results)
});
}.bind(this));
}.bind(this));
However, this can also be solved by passing a callback to setState instead of the object. This way, we get to look at state after any previous queued updates have occurred.
It's also possible to pass a function with the signature function(state, props). This can be useful in some cases when you want to enqueue an atomic update that consults the previous value of state+props before setting any values.
– Component Api Docs
this.setState({
isLoading: true,
results: null
});
$.get(ajaxUrl, function(results) {
this.setState(function(state){
return {
isLoading: false,
results: state.results.concat(results)
};
});
}.bind(this));
For best results, abstract all of this into a high order component or mixin. You don't want to deal with this logic in every component that's fetching data.
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