React router v6 doesn't render when moving to link with fewer path elements

Viewed 86

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?

0 Answers
Related