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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25145857/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 04:02:33  来源:igfitidea点击:

React.js having state based on other state

javascriptreactjs

提问by Andrew

I'm running into some problems with React.js and the state not being immediately set when calling setState(). I'm not sure if there are better ways to approach this, or if it really is just a shortcoming of React. I have two state variables, one of which is based on the other. (Fiddle of original problem: http://jsfiddle.net/kb3gN/4415/you can see in the logs that it's not set right away when you click the button)

我遇到了 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
  });
}, ...

When calling setAlarmTime, since this.state.alarmTimeisn't updated immediately, the following call to checkAlarmsets alarmSetbased on the previous value of this.state.alarmTimeand is therefore incorrect.

调用 时setAlarmTime,由于this.state.alarmTime不会立即更新,因此基于 和 的先前值对checkAlarmset的以下调用是不正确的。alarmSetthis.state.alarmTime

I solved this by moving the call to checkAlarminto the callback of setStatein setAlarmTime, but having to keep track of what state is actually 'correct' and try to fit everything into callbacks seems ridiculous:

我通过将调用移动checkAlarmsetStatein的回调中解决了这个问题setAlarmTime,但是必须跟踪什么状态实际上是“正确的”并尝试将所有内容都放入回调中似乎很荒谬:

setAlarmTime: function(time) {
  this.setState({ alarmTime: time }, this.checkAlarm);
}

Is there a better way to go about this? There are a few other places in my code which I reference state I just set and now I'm unsure as to when I can actually trust the state!

有没有更好的方法来解决这个问题?我的代码中还有一些其他地方引用了我刚刚设置的状态,现在我不确定何时可以真正信任状态!

Thanks

谢谢

采纳答案by Douglas

Yes, setStateis asynchronous, so this.statewon't be updated immediately. Here are the unit testsfor batching, which might explain some of the details.

是的,setState是异步的,所以this.state不会立即更新。下面是批处理的单元测试,它可以解释一些细节。

In the example above, alarmSetis data computed from the alarmTimeand elapsedTimestate. Generally speaking, computed data shouldn't be stored in the state of the object, instead it should be computed as-needed as part of the render method. There is a section What Shouldn'tGo in State?at the bottom of the Interactivity and Dynamic UIs docs which gives examples of things like this which shouldn't go in state, and the What Components Should Have State?section explains some of the reasons why this might be a good idea.

在上面的例子中,alarmSet数据是从alarmTimeelapsedTime状态计算出来的。一般来说,计算数据不应该存储在对象的状态中,而是应该作为渲染方法的一部分按需计算。有一个部分什么不应该进入状态?在交互性和动态 UI 文档的底部,提供了不应进入状态的此类示例,以及哪些组件应该具有状态?部分解释了为什么这可能是一个好主意的一些原因。

回答by Andrew

As Douglas stated, it's generally not a good idea to keep computed state in this.state, but instead to recompute it each time in the component's renderfunction, since the state will have been updated by that point.

正如 Douglas 所说,将计算状态保持在 中通常不是一个好主意this.state,而是每次在组件的render函数中重新计算它,因为到那时状态已经更新。

However this won't work for me, as my component actually has its own update loop which needs to check and possibly update its state at every tick. Since we cannot count on this.stateto have been updated at every tick, I created a workaround that wraps React.createClassand adds it's own internal state tracking. (Requires jQuery for $.extend) (Fiddle: http://jsfiddle.net/kb3gN/4448/)

但是,这对我不起作用,因为我的组件实际上有自己的更新循环,它需要在每个滴答声中检查并可能更新其状态。由于我们不能指望this.state在每个滴答声中都进行更新,因此我创建了一个解决方法来包装React.createClass并添加它自己的内部状态跟踪。($.extend 需要 jQuery)(小提琴: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);
          }
        }
      )
    );
  }
}

For any components where you need up-to-date state outside of the render function, just replace the call to React.createClasswith Utils.createClass.

对于您需要跟上时代的状态呈现功能之外的任何部件,只需更换呼叫React.createClassUtils.createClass

You'll also have to change all this.setStatecalls with this._setStateand this.statecalls with this._state.

您还可以改变所有this.setState的调用this._setStatethis.state使用电话this._state

One last consequence of doing this is that you'll lose the auto-generated displayNameproperty in your component. This is due to the jsx transformer replacing

这样做的最后一个后果是您将丢失displayName组件中自动生成的属性。这是由于 jsx 变压器替换

var anotherComponent = React.createClass({

var anotherComponent = React.createClass({

with

var anotherComponent = React.createClass({displayName: 'anotherComponent'.

var anotherComponent = React.createClass({displayName: 'anotherComponent'.

To get around this, you'll just have to manually add in the displayName property to your objects.

要解决这个问题,您只需手动将 displayName 属性添加到您的对象中。

Hope this helps

希望这可以帮助

回答by Alex B.

Unsure if this was the case when question was asked, though now the second parameter of this.setState(stateChangeObject, callback)takes an optional callback function, so can do this:

不确定在提出问题时是否是这种情况,尽管现在的第二个参数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
  });
}, ...