在 setState() 的回调中发出 AJAX 请求

Issuing AJAX request in the callback of setState()

我一直在像这样编写我的 ReactJS AJAX 请求:

this.setState({
    isLoading: true,
    results: null
});
$.get(ajaxUrl, function(results) {
    this.setState({
        isLoading: false,
        results: results
    });
}.bind(this));

这只是一个示例,它缺少错误处理、限制、取消请求等。但要点就在那里。我基本上要求设置一些状态,然后然后发出请求。

查看 GitHub 上的一些其他代码,不过,我注意到有些人在 setState 回调中编写了他们的 AJAX 调用:

this.setState({
    isLoading: true,
    results: null
}, function() {
    $.get(ajaxUrl, function(results) {
        this.setState({
            isLoading: false,
            results: results
        });
    }.bind(this));
}.bind(this));

这样做有正当理由吗? The docs say:

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

所以不能保证 setState 在返回之前改变状态,但我没有看到不同的 setState 可能会乱序执行。所以可能发生的最坏情况是 "loading" 状态永远不会被渲染。这是后一种风格试图解决的问题吗?还有其他我没有看到的风险吗?

but I see no mention that different setState's may execute out of order

更正它们的顺序 运行,从用户体验的角度来看,您不希望显示加载指示器的时间少于半秒。

需要这个的情况看起来更像这样:

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));

不过,这也可以通过将回调传递给 setState 而不是对象来解决。这样,我们就可以在任何先前排队的更新发生后查看状态。

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));

为了获得最佳结果,请将所有这些抽象为高阶组件或混入。您不想在每个获取数据的组件中处理此逻辑。