I am trying to utilize nested routes in order to maintain the appearance of a parent component on screen, and as the user navigates left and right in a tab structure, the content in that tabbed interface updates. I do not want the parent component to remount or even re-render, only it's children to change. This is a completely keyboard-based navigation system, so we are not using Links or click events, just hitting left/right/up/down/enter on the keyboard.
Unfortunately, I cannot share my exact code for privacy reasons, but here is the general code structure (obviously not compilable, just to get the gist of what our architecture is like).
in App.js
class App extends Component {
render() {
return (
<div className="App">
<Switch>
<Route
path="/"
exact
match={ true }
component={ () => <MainMenu/> }
/>
<Route
path="/category/:uniqueID"
exact
component={ () => <CategoryComponent childArray=[child1, child2, child3] /> }
/>
/>
</Switch>
</div>
);
}
}
in CategoryComponent.js
class CategoryComponent extends Component {
render() {
var childRoutes;
this.props.childArray.forEach(child => {
childRoutes.push(
<Route
key=child.id
path={ `${this.props.match.path}/${child.path}` }
component={ () => <ChildComponent/> }
/>
);
});
return (
<div className="CategoryComponent">
... // a bunch of UI stuff goes here, including the navigation for the child components
<Switch>
{ childRoutes }
</Switch>
</div>
);
}
}
and finally, in the ChildComponent.js
class ChildComponent extends Component {
shouldComponentUpdate(nextProps) {
// because this navigation is done exclusively by keyboard,
// each child has a property of selected or not that it gets from its parent,
// so only the currently selected one should actually be doing the redirect
if (!this.props.isSelected && nextProps.isSelected) {
this.redirect = true;
}
}
render() {
var redirect;
if (this.redirect) {
redirect =
<Redirect
to={ `${this.props.match.path}/${this.props.thisChildPath}` }
/>;
}
return (
<div className="ChildComponent">
{ redirect }
</div>
);
}
}
Hopefully all of the above made sense, it's as simple as I think I can make it from our crazy complex application. Basically:
The problem I am having is that it seems no matter where I place the redirects, if I use exact or (non-exact paths), or if I use push as true in the Redirect, the parent component ALWAYS remounts. I end up with an entirely new parent component, which will wipe out certain elements saved in local state. The App never remounts, but the Parent Component does. I only want the Child Components to remount, the parent should stay exactly as is. Originally the Category component was even a Higher Order Component, and we switched this to just one normal component class, but with or without conditionally rendering specific cases, didn't seem to make any different either.
Also, I have been playing around with this codesandbox, and adapted the original code to more closely match my project and utilize both links and redirects, and the parent app component never seemed to remount. So...it SEEMS like it's possible, I'm just not sure what I'm doing wrong.
Any help would be greatly appreciated :) thanks!
The Redirect component was usually used in previous versions of the react-router-dom package to quickly do redirects by simply importing the component from react-router-dom and then making use of the component by providing the to prop, passing the page you desire to redirect to.
To redirect to another page on button click in React: Use the useNavigate() hook, e.g. const navigate = useNavigate(); . Call the navigate() function, passing it the path - navigate('/about') . The navigate() function lets us navigate programmatically.
To go back to the previous page, pass -1 as a parameter to the navigate() function, e.g. navigate(-1) . Calling navigate with -1 is the same as hitting the back button. Similarly, you can call the navigate function with -2 to go 2 pages back.
This helped me out a ton: https://github.com/ReactTraining/react-router/issues/6122
I realized that our App's Switch Routing was using component
, which was causing the reconstruction every time. By switching those all to render
, the problem was solved :D
So App.js became this:
class App extends Component {
render() {
return (
<div className="App">
<Switch>
<Route
path="/"
exact
match={ true }
render={ () => <MainMenu/> }
/>
<Route
path="/category/:uniqueID"
exact
render={ () => <CategoryComponent childArray=[child1, child2, child3] /> }
/>
/>
</Switch>
</div>
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With