我在给定的路由上有一个组件,比如app.com/cars/1
我有一个侧边栏链接到不同的汽车,如/cars/2
, /cars/3
等
我遇到的问题是,当你改变链接,说从cars/1
到cars/2
,组件不卸载,我得到componentWillReceiveProps
解雇。如果我转到另一个具有不同组件的页面,例如/trucks
,则该组件被卸载,一切正常。
当路由改变时,如何卸载我的组件?我要为下一辆车清除各种状态和通量的东西。或者,如果没有卸载,人们处理这类问题的典型方法是什么?我无法想象这不是很常见。
(注意我使用的是react-router)
我认为处理这个问题的正常方法是在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
}
但是,如果你真的想重新挂载你的组件,你可以使用以下几个选项:
如果你不想让任何组件在路由更改时仍然挂载,你可以利用路由器的createElement
选项为组件添加一个唯一的密钥:
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}
);
}
最后我做了:
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>
);
并忽略潜在的性能问题(如果它们发生的话),在我看来,维护成本(重置:dynamic-segment下所有组件的状态,在componentWillReceiveProps中重新获取数据等)是不值得的。
我选择了带有change key的Michelle Tilley选项,但是我没有为路由器中的整个组件设置key,而只是为需要通过重启钩子进行更新的组件设置key。
const UniqComponent = () => {
const uniqId = 123; // may be carId
return <div key={uniqId} />
}
ReactDOM.render(
<Router history={browserHistory}>
<Route path="cars/:id" component={UniqComponent}/>
</Router>
);