I'm trying to setup a multi-level browsing pattern with React Router 6.3.0 on React 18.2.0. The pattern I'm trying to get to allows for drilling down into locations with nested paths such as:
/explore
/explore/USA
/explore/USA/Florida
The same component is able to process any of the routes by taking everything beyond the base as additional parameters. The routes are setup like this:
<BrowserRouter>
<Routes>
<Route path='/explore'>
<Route index element={<ExplorePath />} />
<Route path=':p1' element={<ExplorePath />} />
<Route path=':p1/:p2' element={<ExplorePath />} />
<Route path=':p1/:p2/:p3' element={<ExplorePath />} />
<Route path=':p1/:p2/:p3/:p4' element={<ExplorePath />} />
<Route path=':p1/:p2/:p3/:p4/:p5' element={<ExplorePath />} />
<Route path=':p1/:p2/:p3/:p4/:p5/:p6' element={<ExplorePath />} />
</Route>
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
Sounds simple. Drilling down works fine. As I go to each deeper level the content renders as expected. The problem starts when trying to move up the train. I have breadcrumbs setup with the <Link> compontent. If I click on one for a higher level (such as "/explore/USA" when I'm looking at "/explore/USA/Florida") the URL updates as expected but the content does not update at all.
The only workaround I've found so far is to add the reloadDocument to my <Link> tags. This works, but it forces a page reload every time I navigate.
Is there a way to configure the routes to make the component re-render without forcing a full page reload?
Update 21-Jul-2022:
It isn't a fix, but I did find a workaround. Digging deeper, this seems to be an issue with how a React function and a React component work. First off, extracting route parameters in a component appears to be very messy (if possible at all). To get around it I created the following React function:
export function ExplorePath() {
const { p1, p2, p3, p4, p5, p6 } = useParams();
const parts = [p1, p2, p3, p4, p5, p6];
const trimmed = parts.filter(o => o !== undefined);
const path = trimmed.join('/');
return (
<Explore path={path} />
);
}
The function is being called any time I click a link that calls one of the defined routes. However, it appears that when the function calls the component it is reusing the component when navigating to a shorter path instead of creating a new one. As I drill down the tree I always end up with a new component. The workaround I ended up with is to check for a change in the props with componentDidUpdate like this:
constructor(props) {
super(props);
this.state = { isLoading: true, model: null };
}
componentDidMount() {
this.populateModel();
}
componentDidUpdate(prevProps: PageProps) {
if (this.props.path !== prevProps.path) {
this.setState({ isLoading: true, model: null });
this.populateModel();
}
}
So, did I find a bug in how React functions and components interact or is this just a quirk that I'm not understanding?