我遇到了React.js的一些问题,并且在调用setState()时没有立即设置状态。我不确定是否有更好的方法来解决这个问题,或者它是否真的只是React的一个缺点。我有两个状态变量,其中一个是基于另一个。 (原始问题的小提示:http://jsfiddle.net/kb3gN/4415/您可以在日志中看到单击按钮时没有立即设置
setAlarmTime: function(time) {
this.setState({ alarmTime: time });
this.checkAlarm();
},
checkAlarm: function() {
this.setState({
alarmSet: this.state.alarmTime > 0 && this.state.elapsedTime < this.state.alarmTime
});
}, ...
在致电setAlarmTime
时,由于this.state.alarmTime
没有立即更新,以下对checkAlarm
的调用会根据{{1}的先前值设置alarmSet
因此是不正确的。
我通过将this.state.alarmTime
的调用转移到checkAlarm
中setState
的回调来解决了这个问题,但必须跟踪实际状态是什么状态&#39;正确&#39;并尝试将所有内容都放入回调中似乎很荒谬:
setAlarmTime
还有更好的方法吗?在我的代码中有一些其他地方我引用我刚设置的状态,现在我不确定何时能够真正信任该状态!
由于
答案 0 :(得分:20)
是的,setState是异步的,因此this.state
不会立即更新。以下是批处理的unit tests,可以解释一些细节。
在上面的示例中,alarmSet
是根据alarmTime
和elapsedTime
状态计算的数据。一般而言,计算数据不应存储在对象的状态中,而应根据需要计算,作为渲染方法的一部分。 Interactivity和Dynamic UIs文档底部有一个What Shouldn’t Go in State?部分,它提供了不应该进入状态的类似事例,What Components Should Have State?部分解释了为什么会出现这种情况的一些原因是一个好主意。
答案 1 :(得分:2)
正如Douglas所说,在this.state
中保持计算状态通常不是一个好主意,而是每次在组件的render
函数中重新计算它,因为状态将由此更新点。
然而,这对我来说不起作用,因为我的组件实际上有自己的更新循环,需要检查并可能在每次滴答时更新其状态。由于我们不能指望this.state
在每个刻度都更新,我创建了一个包含React.createClass
的解决方法,并添加了自己的内部状态跟踪。 (需要jQuery for $ .extend)(小提琴:http://jsfiddle.net/kb3gN/4448/)
var Utils = new function() {
this.createClass = function(object) {
return React.createClass(
$.extend(
object,
{
_state: object.getInitialState ? object.getInitialState() : {},
_setState: function(newState) {
$.extend(this._state, newState);
this.setState(newState);
}
}
)
);
}
}
对于在渲染函数之外需要最新状态的任何组件,只需将React.createClass
的调用替换为Utils.createClass
。
您还必须使用this.setState
通过this._setState
和this.state
来电更改所有this._state
来电。
执行此操作的最后一个后果是您将丢失组件中自动生成的displayName
属性。这是由于jsx变换器替换
var anotherComponent = React.createClass({
与
var anotherComponent = React.createClass({displayName: 'anotherComponent'
。
要解决此问题,您只需手动将displayName属性添加到对象中即可。
希望这有帮助
答案 2 :(得分:1)
不确定是否在询问问题时是这种情况,但现在this.setState(stateChangeObject, callback)
的第二个参数采用可选的回调函数,所以可以这样做:
setAlarmTime: function(time) {
this.setState({ alarmTime: time }, this.checkAlarm);
},
checkAlarm: function() {
this.setState({
alarmSet: this.state.alarmTime > 0 && this.state.elapsedTime < this.state.alarmTime
});
}, ...