React.js具有基于其他状态的状态

时间:2014-08-05 18:27:39

标签: javascript reactjs

我遇到了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的调用转移到checkAlarmsetState的回调来解决了这个问题,但必须跟踪实际状态是什么状态&#39;正确&#39;并尝试将所有内容都放入回调中似乎很荒谬:

setAlarmTime

还有更好的方法吗?在我的代码中有一些其他地方我引用我刚设置的状态,现在我不确定何时能够真正信任该状态!

由于

3 个答案:

答案 0 :(得分:20)

是的,setState是异步的,因此this.state不会立即更新。以下是批处理的unit tests,可以解释一些细节。

在上面的示例中,alarmSet是根据alarmTimeelapsedTime状态计算的数据。一般而言,计算数据不应存储在对象的状态中,而应根据需要计算,作为渲染方法的一部分。 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._setStatethis.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
  });
}, ...