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
React.js having state based on other state
提问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.alarmTime
isn't updated immediately, the following call to checkAlarm
sets alarmSet
based on the previous value of this.state.alarmTime
and is therefore incorrect.
调用 时setAlarmTime
,由于this.state.alarmTime
不会立即更新,因此基于 和 的先前值对checkAlarm
set的以下调用是不正确的。alarmSet
this.state.alarmTime
I solved this by moving the call to checkAlarm
into the callback of setState
in setAlarmTime
, but having to keep track of what state is actually 'correct' and try to fit everything into callbacks seems ridiculous:
我通过将调用移动checkAlarm
到setState
in的回调中解决了这个问题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.state
won't be updated immediately. Here are the unit testsfor batching, which might explain some of the details.
是的,setState是异步的,所以this.state
不会立即更新。下面是批处理的单元测试,它可以解释一些细节。
In the example above, alarmSet
is data computed from the alarmTime
and elapsedTime
state. 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
数据是从alarmTime
和elapsedTime
状态计算出来的。一般来说,计算数据不应该存储在对象的状态中,而是应该作为渲染方法的一部分按需计算。有一个部分什么不应该进入状态?在交互性和动态 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 render
function, 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.state
to have been updated at every tick, I created a workaround that wraps React.createClass
and 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.createClass
with Utils.createClass
.
对于您需要跟上时代的状态呈现功能之外的任何部件,只需更换呼叫React.createClass
用Utils.createClass
。
You'll also have to change all this.setState
calls with this._setState
and this.state
calls with this._state
.
您还可以改变所有this.setState
的调用this._setState
和this.state
使用电话this._state
。
One last consequence of doing this is that you'll lose the auto-generated displayName
property 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
});
}, ...