我在给定路线上有一个组件,比如app.com/cars/1
我有一个侧边栏,其中包含指向不同车辆的链接,例如/cars/2
,/cars/3
等。
我遇到的问题是当您更改链接时,例如从cars/1
转到cars/2
,组件无法卸载,我被componentWillReceiveProps
解雇了。如果我转到另一个包含不同组件的页面,例如/trucks
,则组件已卸载且一切正常。
当路线发生变化时,如何卸载组件?我有各种状态和助焊剂的东西,我想清除下一辆车。或者如果没有卸载,人们会处理这类问题的典型方式吗?我无法想象这不是很常见。
(注意我正在使用react-router)
答案 0 :(得分:13)
我认为处理此问题的正常方法是在componentWillReceiveProps
中取消注册并重新注册您的侦听器,重置您的状态等。围绕此行为创建抽象是正常的:
componentWillMount: function() {
this.setupStuff(this.props);
}
componentWillUnmount: function() {
this.tearDownStuff();
}
componentWillReceiveProps: function(nextProps) {
this.tearDownStuff();
this.setupStuff(nextProps);
}
setupStuff: function(props) {
this.setState(this.getDataFromStore(props.store));
props.store.listen(this.handler); // or whatever
}
tearDownStuff: function(props) {
props.store.unlisten(this.handler); // or whatever
}
但是,如果您真的想重新安装组件,可以使用几种选项。
如果您不希望任何组件在路由更改中保持挂载,则可以使用路由器的the createElement
option为组件添加唯一键:
function createElement(Component, props) {
var key = ...; // some key that changes across route changes
return <Component key={key} {...props} />;
}
// ...
<Router createElement={createElement}>
...
但是,我不建议这样做。它不仅使你的应用程序变慢,因为每次每个路由组件都在重新安装,但它也完全禁用了具有不同道具的相同路由处理程序的后续渲染之间的动画。
如果您只想要某些路由始终重新呈现,您可以通过React.cloneElement
在父级中为其指定密钥:
render: function() {
var key = ...; // some key that changes across route changes
return React.cloneElement(
React.Children.only(this.props.children),
{key: key}
);
}
答案 1 :(得分:2)
我最后刚刚做了:
const createElement = (Component, props) =>
<Component key={props.params.id} {...props}/>;
ReactDOM.render(
<Router history={browserHistory} createElement={createElement}>
<Route path="courses/:id" component={Page_courses_id}/>
</Router>
);
并且忽略了潜在的性能问题(如果它们曾经发生过),在我看来,维护成本(重置所有组件的状态:动态段,重新获取componentWillReceiveProps中的数据等)是不值得的。
答案 2 :(得分:0)
我选择了带有更改密钥的 Michelle Tilley 选项,但我没有为路由器中的整个组件设置密钥,而是只为需要通过重新启动挂钩进行更新的那个组件设置密钥。
这很好用。
const UniqComponent = () => {
const uniqId = 123; // may be carId
return <div key={uniqId} />
}
ReactDOM.render(
<Router history={browserHistory}>
<Route path="cars/:id" component={UniqComponent}/>
</Router>
);