Reputation: 5361
I have a component at a given route, say app.com/cars/1
I have a sidebar with links to different cars, eg /cars/2
, /cars/3
etc.
The issue I'm having is when you change links, say go from cars/1
to cars/2
, the component doesn't unmount, and I get componentWillReceiveProps
fired. If I go to another page with a different component, say /trucks
, the component is unmounted and all is well.
How can I unmount my component when the route changes? I have all kinds of state and flux stuff that I want cleared for this next car. Or if not unmount, is there a typical way people handle this kind of issue? I can't imagine this isn't very common.
(note I'm using react-router)
Upvotes: 19
Views: 17567
Reputation: 11
I chose the Michelle Tilley option with change key, but I did not set the key for the entire component in the router, but only for the one where I needed to update with restarting the hooks.
This works great.
const UniqComponent = () => {
const uniqId = 123; // may be carId
return <div key={uniqId} />
}
ReactDOM.render(
<Router history={browserHistory}>
<Route path="cars/:id" component={UniqComponent}/>
</Router>
);
Upvotes: 1
Reputation: 11202
I ended up just doing:
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>
);
and ignoring potential performance issues (if they ever occur), in my mind maintenance cost (of resetting state of all components under :dynamic-segment, of refetching data in componentWillReceiveProps, etc.) is not worth it.
Upvotes: 3
Reputation: 159095
I think the normal way to handle this is just to unregister and reregister your listeners, reset your state, and so on in componentWillReceiveProps
. It's normal to create abstractions around this behavior:
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
}
However, if you really wanted to remount your components, there are a couple options you can use.
If you don't want any of your components to remain mounted across route changes, you can utilize the createElement
option of the router to add a unique key to the components:
function createElement(Component, props) {
var key = ...; // some key that changes across route changes
return <Component key={key} {...props} />;
}
// ...
<Router createElement={createElement}>
...
However, I don't recommend this. Not only does it make your app slower because every route component is remounting each time, but it also completely disables things like animations between subsequent renders of the same route handler with different props.
If you only want a certain route to always rerender, you can give it a key in the parent via React.cloneElement
:
render: function() {
var key = ...; // some key that changes across route changes
return React.cloneElement(
React.Children.only(this.props.children),
{key: key}
);
}
Upvotes: 17