Javascript 如何强制重新安装 React 组件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35792275/
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
How to force remounting on React components?
提问by o01
Lets say I have a view component that has a conditional render:
假设我有一个具有条件渲染的视图组件:
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 looks something like this:
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>
);
}
}
Lets say employed
is true. Whenever I switch it to false and the other view renders, only unemployment-duration
is re-initialized. Also unemployment-reason
gets prefilled with the value from job-title
(if a value was given before the condition changed).
可以说employed
是真的。每当我将其切换为 false 并且其他视图呈现时,只会unemployment-duration
重新初始化。还unemployment-reason
预填充了来自的值job-title
(如果在条件更改之前给出了值)。
If I change the markup in the second rendering routine to something like this:
如果我将第二个渲染例程中的标记更改为如下所示:
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>
);
}
}
It seems like everything works fine. Looks like React just fails to diff 'job-title' and 'unemployment-reason'.
似乎一切正常。看起来 React 无法区分“职位”和“失业原因”。
Please tell me what I'm doing wrong...
请告诉我我做错了什么...
回答by Alex K
Change the key of the component.
更改组件的键。
<Component key="1" />
<Component key="2" />
Component will be unmounted and a new instance of Component will be mounted since the key has changed.
由于密钥已更改,因此将卸载 Component 并安装 Component 的新实例。
edit: Documented on You Probably Don't Need Derived State:
编辑:记录在您可能不需要派生状态:
When a key changes, React will create a new component instance rather than update the current one. Keys are usually used for dynamic lists but are also useful here.
当一个键发生变化时,React 会创建一个新的组件实例而不是更新当前的组件实例。键通常用于动态列表,但在这里也很有用。
回答by Chris
What's probably happening is that React thinks that only one MyInput
(unemployment-duration
) is added between the renders. As such, the job-title
never gets replaced with the unemployment-reason
, which is also why the predefined values are swapped.
可能发生的情况是 React 认为在渲染之间只添加了一个MyInput
( unemployment-duration
)。因此,job-title
永远不会被替换为unemployment-reason
,这也是交换预定义值的原因。
When React does the diff, it will determine which components are new and which are old based on their key
property. If no such key is provided in the code, it will generate its own.
当 React 进行 diff 时,它会根据它们的key
属性确定哪些组件是新的,哪些是旧的。如果代码中没有提供这样的密钥,它将生成自己的密钥。
The reason why the last code snippet you provide works is because React essentially needs to change the hierarchy of all elements under the parent div
and I believe that would trigger a re-render of all children (which is why it works). Had you added the span
to the bottom instead of the top, the hierarchy of the preceding elements wouldn't change, and those element's wouldn't re-render (and the problem would persist).
您提供的最后一个代码片段之所以有效是因为 React 本质上需要更改父级下所有元素的层次结构,div
我相信这会触发所有子级的重新渲染(这就是它起作用的原因)。如果您将 the 添加span
到底部而不是顶部,则前面元素的层次结构不会改变,并且这些元素不会重新呈现(并且问题会持续存在)。
Here's what the official React documentationsays:
The situation gets more complicated when the children are shuffled around (as in search results) or if new components are added onto the front of the list (as in streams). In these cases where the identity and state of each child must be maintained across render passes, you can uniquely identify each child by assigning it a key.
When React reconciles the keyed children, it will ensure that any child with key will be reordered (instead of clobbered) or destroyed (instead of reused).
当子项被随机排列时(如在搜索结果中)或者如果将新组件添加到列表的前面(如在流中),情况会变得更加复杂。在这些必须跨渲染通道维护每个子项的身份和状态的情况下,您可以通过为其分配一个键来唯一标识每个子项。
当 React 协调有键的孩子时,它将确保任何有键的孩子都将被重新排序(而不是破坏)或销毁(而不是重用)。
You should be able to fix this by providing a unique key
element yourself to either the parent div
or to all MyInput
elements.
您应该能够通过key
自己为父元素div
或所有MyInput
元素提供唯一元素来解决此问题。
For example:
例如:
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>
);
}
}
Now, when React does the diff, it will see that the divs
are different and will re-render it including all of its' children (1st example). In the 2nd example, the diff will be a success on job-title
and unemployment-reason
since they now have different keys.
现在,当 React 进行 diff 时,它会看到divs
它们不同,并将重新渲染它,包括它的所有子元素(第一个示例)。在第二个示例中,差异将成功job-title
,unemployment-reason
因为它们现在具有不同的键。
You can of course use any keys you want, as long as they are unique.
您当然可以使用任何您想要的键,只要它们是唯一的。
Update August 2017
2017 年 8 月更新
For a better insight into how keys work in React, I strongly recommend reading my answer to Understanding unique keys in React.js.
为了更好地了解键在 React 中的工作原理,我强烈建议阅读我对理解 React.js 中的唯一键的回答。
Update November 2017
2017 年 11 月更新
This update should've been posted a while ago, but using string literals in ref
is now deprecated. For example ref="job-title"
should now instead be ref={(el) => this.jobTitleRef = el}
(for example). See my answer to Deprecation warning using this.refsfor more info.
此更新应该在不久前发布,但ref
现在不推荐使用字符串文字。例如ref="job-title"
现在应该改为ref={(el) => this.jobTitleRef = el}
(例如)。有关详细信息,请参阅我使用 this.refs对弃用警告的回答。
回答by Dmitriy
Use setState
in your view to change employed
property of state. This is example of React render engine.
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>
);
}
}
回答by Ruben Verster
I'm working on Crud for my app. This is how I did it Got Reactstrap as my dependency.
我正在为我的应用程序开发 Crud。这就是我做的方式 将 Reactstrap 作为我的依赖项。
import React, { useState, setState } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import firebase from 'firebase';
// import { LifeCrud } from '../CRUD/Crud';
import { Row, Card, Col, Button } from 'reactstrap';
import InsuranceActionInput from '../CRUD/InsuranceActionInput';
const LifeActionCreate = () => {
let [newLifeActionLabel, setNewLifeActionLabel] = React.useState();
const onCreate = e => {
const db = firebase.firestore();
db.collection('actions').add({
label: newLifeActionLabel
});
alert('New Life Insurance Added');
setNewLifeActionLabel('');
};
return (
<Card style={{ padding: '15px' }}>
<form onSubmit={onCreate}>
<label>Name</label>
<input
value={newLifeActionLabel}
onChange={e => {
setNewLifeActionLabel(e.target.value);
}}
placeholder={'Name'}
/>
<Button onClick={onCreate}>Create</Button>
</form>
</Card>
);
};
Some React Hooks in there
那里有一些 React Hooks