我一直在编写像我这样的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"状态永远不会被渲染。这是后一种风格试图解决的问题吗?还有其他风险我看不到吗?
答案 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。您不希望在每个获取数据的组件中处理此逻辑。