在setState()

时间:2015-04-30 16:36:46

标签: ajax concurrency reactjs

我一直在编写像我这样的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

  

无法保证对setState的调用进行同步操作,并且可以对调用进行批处理以获得性能提升。

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

1 个答案:

答案 0 :(得分:3)

  

但我没有提到不同的setState可能无序执行

纠正它们是按顺序运行的,从用户体验的角度来看,你不想在不到半秒的时间内显示加载指示。

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

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而不是对象来解决。这样,我们可以在发生任何先前排队的更新之后查看状态。

  

也可以使用签名功能(状态,道具)传递函数。在某些情况下,如果您希望在设置任何值之前将原子更新排入队列,那么它可以用于查询state + props的先前值。
   - 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));

为获得最佳效果,请将所有这些内容抽象为高阶组件或mixin。您不希望在每个获取数据的组件中处理此逻辑。