I want to make a drilldown view of job list > test list > individual test. These should be mapped to the routes /
, /jobs/:jobid
, and /jobs/:jobid/tests/:testid
respectively, and when the route changes levels I want to make my drilldown view slide horizontally. However, with react-router 0.13.3, the same handler for each of the routes gets remounted when I change routes, which would prevent any animation.
Here's some test code demonstrating this:
var AppShellHandler = React.createClass({
componentDidMount() {
console.log("Mounted!");
},
render() {
return <h1>{JSON.stringify(this.props, null, " ")}</h1>;
}
});
var Routes = <Route path="/">
<DefaultRoute handler={AppShellHandler} />
<Route path="jobs/:jobid">
<DefaultRoute handler={AppShellHandler} />
<Route path="tests/:testid">
<DefaultRoute handler={AppShellHandler} />
</Route>
</Route>
</Route>;
Router.run(Routes, Handler => React.render(<Handler/>, document.getElementById('content')));
So I ran this and changed the route from /
to /jobs/1234
by manually typing in the URL bar, and it printed Mounted!
in the console.
I see no need to remount the handler when it's the same element. I guess I'll just have to use a /*
for my route and manually parse params.splat
, but it would be nice if react-router provided convenient support for animated route transitions.
Good heavens, what was I thinking? Not only is the remount caused by the React.render
, which is under my control, the nested routes I have wouldn't work logically to begin with. This config worked without problems:
var Routes = <Route path="/" handler={AppShellHandler}>
<Route path="jobs/:jobId/tests/:testId" handler={PressureTestDrilldownCV}/>
<Route path="jobs/:jobId" handler={PressureTestDrilldownCV}/>
<DefaultRoute handler={PressureTestDrilldownCV}/>
</Route>;
Router.run(Routes, Handler => React.render(<Handler/>, document.getElementById('content')));
I have also encountered this problem. I just want to mention that my problem was that when the path changes only the render() function run again so all the logic in the constructor and componentDidMount will not run again. So put the logic that should happen when entering the page in the render function or maybe there is a better option (I do not know)
Hope this helps someone
I also ran into this problem, I'm using componentWillReceiveProps instead. This function will be called when the route changed, so it's better to handle all the state changes in this method instead of render function.
I'm using Alt to implement the flux structure, what I wanted to do was to completely reset the state and do the whole actions (getting the data from the server and similar actions) again on route change.
What I ended up doing was to define a variable in the constructor that I named allSet
and used it to check the route change and wether the data should be reset or not as below:
class Person extends React.Component {
constructor(props) {
super(props);
this.state = PersonStore.getState();
this.type = this.props.location.pathname.split('/')[1]; //this is the name of the route
this.onChange = this.onChange.bind(this);
this.allSet=false;
}
componentDidMount() {
PersonStore.listen(this.onChange);
//...get the data from the server...
this.allSet=true;
}
componentWillReceiveProps(nextProps){
if(this.type!==nextProps.location.pathname.split('/')[1]){ //the route has changed
this.allSet=false;
this.type = nextProps.location.pathname.split('/')[1];
alt.recycle(PersonStore); //this will trigger the onChange method with the reseted state
}
}
onChange(state) {
if(!this.allSet){ //means state is reset and need to get the new data
this.allSet=true;
//...get the data from the server...
}
this.setState(state);
}
//...
}
I have also encountered this problem, giving a key property to the components solves the problem.
for example:
<Route path={path1} render={(props) => { return (<Common key={key1} />); }}/>
<Route path={path2} render={(props) => { return (<Common key={key2} />); }}/>
<Route path={path3} render={(props) => { return (<Common key={key3} />); }}/>
@gostavee adding key to component fixes the issue but it leads to componentDidMount running twice as react reconciliation unmounts and remount on getting a different key
@sayedatif actually the keys in @gostavee's example shouldn't make any difference regardless because the <Common>
elements are mounted under different <Route>
s. Even if all the <Common>
elements had the same key
in that example it wouldn't prevent an unmount/remount.
Most helpful comment
I also ran into this problem, I'm using componentWillReceiveProps instead. This function will be called when the route changed, so it's better to handle all the state changes in this method instead of render function.