假设我有一个具有条件渲染的视图组件:
render(){
if (this.state.employed) {
return (
<div>
<MyInput ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div>
<MyInput ref="unemployment-reason" name="unemployment-reason" />
<MyInput ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
MyInput看起来像这样:
class MyInput extends React.Component {
...
render(){
return (
<div>
<input name={this.props.name}
ref="input"
type="text"
value={this.props.value || null}
onBlur={this.handleBlur.bind(this)}
onChange={this.handleTyping.bind(this)} />
</div>
);
}
}
让我们说employed
是真的。每当我将其切换为false而其他视图呈现时,只会重新初始化unemployment-duration
。另外unemployment-reason
预先填充了job-title
的值(如果在条件更改之前给出了值)。
如果我将第二个渲染例程中的标记更改为:
render(){
if (this.state.employed) {
return (
<div>
<MyInput ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div>
<span>Diff me!</span>
<MyInput ref="unemployment-reason" name="unemployment-reason" />
<MyInput ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
似乎一切正常。看起来React只是没有分散'职称'和'失业原因'。
请告诉我我做错了什么......
答案 0 :(得分:118)
更改组件的键。
<Component key="1" />
<Component key="2" />
组件将被卸载,并且由于密钥已更改,因此将安装新的Component实例。
修改:记录在You Probably Don't Need Derived State:
当密钥更改时,React将创建一个新的组件实例,而不是更新当前的组件实例。键通常用于动态列表,但在这里也很有用。
答案 1 :(得分:78)
可能发生的事情是React认为在渲染之间只添加了一个MyInput
(unemployment-duration
)。因此,job-title
永远不会被unemployment-reason
取代,这也是交换预定义值的原因。
当React执行diff时,它将根据key
属性确定哪些组件是新组件,哪些组件是旧组件。如果代码中没有提供这样的密钥,它将生成自己的密钥。
你提供的最后一个代码片段起作用的原因是因为React基本上需要更改父div
下所有元素的层次结构,我相信这会触发所有孩子的重新呈现(这就是为什么有用)。如果您将span
添加到底部而不是顶部,则前面元素的层次结构将不会更改,并且这些元素不会重新呈现(并且问题会出现坚持)。
这是官方React documentation所说的:
当孩子们被洗牌时(如在搜索结果中)或者如果新组件被添加到列表的前面(如在流中),情况变得更加复杂。在这些情况下,必须在渲染过程中保持每个孩子的身份和状态,您可以通过为每个孩子分配一个密钥来唯一地识别每个孩子。
当React协调键控子项时,它将确保任何具有键的子项将被重新排序(而不是被破坏)或被销毁(而不是重用)。
您应该可以通过向父key
或所有div
元素提供唯一的MyInput
元素来解决此问题。
例如:
render(){
if (this.state.employed) {
return (
<div key="employed">
<MyInput ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div key="notEmployed">
<MyInput ref="unemployment-reason" name="unemployment-reason" />
<MyInput ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
OR
render(){
if (this.state.employed) {
return (
<div>
<MyInput key="title" ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div>
<MyInput key="reason" ref="unemployment-reason" name="unemployment-reason" />
<MyInput key="duration" ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
现在,当React执行差异时,它会看到divs
不同并将重新呈现它,包括它的所有&#39;儿童(第1个例子)。在第二个示例中,差异将在job-title
和unemployment-reason
上成功,因为它们现在具有不同的密钥。
你当然可以使用你想要的任何键,只要它们是唯一的。
2017年8月更新
为了更好地了解密钥在React中的工作方式,我强烈建议您阅读我对Understanding unique keys in React.js的回答。
2017年11月更新
此更新应该在不久前发布,但现在不推荐使用ref
中的字符串文字。例如,ref="job-title"
现在应该是ref={(el) => this.jobTitleRef = el}
(例如)。有关详细信息,请参阅我对Deprecation warning using this.refs的回答。
答案 2 :(得分:5)
在视图中使用setState
更改州的employed
属性。这是React渲染引擎的示例。
someFunctionWhichChangeParamEmployed(isEmployed) {
this.setState({
employed: isEmployed
});
}
getInitialState() {
return {
employed: true
}
},
render(){
if (this.state.employed) {
return (
<div>
<MyInput ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div>
<span>Diff me!</span>
<MyInput ref="unemployment-reason" name="unemployment-reason" />
<MyInput ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
答案 3 :(得分:0)
我正在为我的应用程序开发Crud。这就是我做到的作为我的依赖项的方式。
print(df[cols].lt(0).any())
b True
c False
dtype: bool
print (df[cols].lt(0).any().reindex(df.columns, fill_value=False))
a False
b True
c False
dtype: bool
其中有一些React钩子