javascript ReactJs:响应状态变化而改变状态
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25798803/
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
ReactJs: change state in response to state change
提问by Emoses
I've got a React component with an input, and an optional "advanced input":
我有一个带有输入的 React 组件和一个可选的“高级输入”:
[ basic ]
Hide Advanced...
[ advanced ]
The advanced on the bottom goes away if you click "Hide Advanced", which changes to "Show Advanced". That's straightforward and working fine, there's a showAdvanced
key in the state that controls the text and whether the advanced input is rendered.
如果您单击“隐藏高级”,底部的高级将消失,它会更改为“显示高级”。这很简单而且工作正常,状态中有一个showAdvanced
键来控制文本以及是否呈现高级输入。
External JS code, however, might change the value of advanced, in which case I want to show the [advanced] input if it's currently hidden and the value is different than the default. The user should be able to click "Hide Advanced" to close it again, however.
但是,外部 JS 代码可能会更改 advanced 的值,在这种情况下,如果 [advanced] 输入当前处于隐藏状态并且该值与默认值不同,我想显示该输入。但是,用户应该能够单击“隐藏高级”以再次关闭它。
So, someone external calls cmp.setState({advanced: "20"})
, and I want to then show advanced; The most straightforward thing to do would just be to update showAdvanced
in my state. However, there doesn't seem to be a way to update some state in response to other state changes in React. I can think of a number of workarounds with slightly different behavior, but I really want to have this specific behavior.
所以,有人外部调用cmp.setState({advanced: "20"})
,然后我想显示高级;最直接的做法就是更新showAdvanced
我的状态。但是,似乎没有一种方法可以更新某些状态以响应 React 中的其他状态更改。我可以想到一些行为略有不同的变通方法,但我真的很想拥有这种特定的行为。
Should I move showAdvanced to props, would that make sense? Can you change props in response to state changes? Thanks.
我应该将 showAdvanced 移到道具上,这有意义吗?你能改变道具以响应状态变化吗?谢谢。
回答by Mike Driver
Okay first up, you mention that a third party outside of your component might call cmp.setState()
? This is a huge react no-no. A component should only ever call it's own setState function - nothing outside should access it.
好的,首先,您提到组件之外的第三方可能会调用cmp.setState()
? 这是一个巨大的反应,不。一个组件应该只调用它自己的 setState 函数——外部的任何东西都不能访问它。
Also another thing to remember is that if you're trying change state again in response to a state change - that means you're doing something wrong.
另外要记住的另一件事是,如果您再次尝试更改状态以响应状态更改 - 这意味着您做错了什么。
When you build things in this way it makes your problem much harder than it needs to be. The reason being that if you accept that nothing external can set the state of your component - then basically the only option you have is to allow external things to update your component's props - and then react to them inside your component. This simplifies the problem.
当您以这种方式构建事物时,它会使您的问题变得比需要的更难。原因是,如果您接受外部无法设置组件状态的事实——那么基本上唯一的选择就是允许外部事物更新组件的 props——然后在组件内部对它们做出反应。这简化了问题。
So for example you should look at having whatever external things that used to be calling cmp.setState()
instead call React.renderComponent
on your component again, giving a new prop or prop value, such as showAdvanced
set to true
. Your component can then react to this in componentWillReceiveProps
and set it's state accordingly. Here's an example bit of code:
因此,例如,您应该查看曾经调用过的任何外部事物,cmp.setState()
而不是React.renderComponent
再次调用您的组件,提供一个新的 prop 或 prop 值,例如showAdvanced
set to true
。然后您的组件可以对此做出反应componentWillReceiveProps
并相应地设置它的状态。这是一个示例代码:
var MyComponent = React.createClass({
getInitialState: function() {
return {
showAdvanced: this.props.showAdvanced || false
}
},
componentWillReceiveProps: function(nextProps) {
if (typeof nextProps.showAdvanced === 'boolean') {
this.setState({
showAdvanced: nextProps.showAdvanced
})
}
},
toggleAdvancedClickHandler: function(e) {
this.setState({
showAdvanced: !this.state.showAdvanced
})
},
render: function() {
return (
<div>
<div>Basic stuff</div>
<div>
<button onClick={this.toggleAdvancedClickHandler}>
{(this.state.showAdvanced ? 'Hide' : 'Show') + ' Advanced'}
</button>
</div>
<div style={{display: this.state.showAdvanced ? 'block' : 'none'}}>
Advanced Stuff
</div>
</div>
);
}
});
So the first time you call React.renderComponent(MyComponent({}), elem)
the component will mount and the advanced div will be hidden. If you click on the button inside the component, it will toggle and show. If you need to force the component to show the advanced div from outside the component simply call render again like so: React.renderComponent(MyComponent({showAdvanced: true}), elem)
and it will show it, regardless of internal state. Likewise if you wanted to hide it from outside, simply call it with showAdvanced: false
.
所以第一次调用React.renderComponent(MyComponent({}), elem)
组件时会挂载,高级 div 会被隐藏。如果您单击组件内的按钮,它将切换并显示。如果您需要强制组件从组件外部显示高级 div,只需像这样再次调用 render :React.renderComponent(MyComponent({showAdvanced: true}), elem)
它会显示它,而不管内部状态如何。同样,如果您想从外部隐藏它,只需使用showAdvanced: false
.
Added bonus to the above code example is that calling setState
inside of componentWillReceiveProps
does not cause another render cycle, as it catches and changes the state BEFORE render
is called. Have a look at the docs here for more info: http://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops
对上述代码示例的额外好处是调用setState
内部componentWillReceiveProps
不会导致另一个渲染周期,因为它会在render
调用之前捕获并更改状态。查看此处的文档以获取更多信息:http: //facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops
Don't forget that calling renderComponent
again on an already mounted component doesn't mount it again, it just tells react to update the component's props
and react will then make the changes, run the lifecycle and render functions of the component and do it's dom diffing magic.
不要忘记renderComponent
再次调用已经安装的组件不会再次安装它,它只是告诉 react 更新组件props
,然后 react 将进行更改,运行组件的生命周期和渲染函数,并执行 dom diffing 魔法.
回答by returneax
Revised answer in comment below.
在下面的评论中修改了答案。
My initial wrong answer:
我最初的错误答案:
The lifecycle function componentWillUpdate
will be ran when new state or props are received. You can find documentation on it here: http://facebook.github.io/react/docs/component-specs.html#updating-componentwillupdate
生命周期函数componentWillUpdate
将在收到新状态或道具时运行。你可以在这里找到它的文档:http: //facebook.github.io/react/docs/component-specs.html#updating-componentwillupdate
If, when the external setState
is called, you then set showAdvanced
to true
in componentWillUpdate
, you should get the desired result.
如果在setState
调用外部函数时设置showAdvanced
为true
in componentWillUpdate
,则应该会得到所需的结果。
EDIT: Another option would be to have the external call to setState
include showAdvanced: true
in its new state.
编辑:另一种选择是将外部调用setState
包含showAdvanced: true
在其新状态中。