Search code examples
reactjsreach-router

Using Reach Router with nested routes fails to parse params


With Reach router (not React router!) I have 2 nested routes:

/g/123 /g/123/about

Where 123 is a :groupId parameter:

import React from "react";
import { Router } from "@reach/router";
import GroupPage from "../components/dynamic-pages/group";
import PostsView from "../components/group/views/posts";
import AboutView from "../components/group/views/about";

const App = () => {
  return (
    <Router>
      <GroupPage path="/g/:groupId">
        <PostsView path="/" />
        <AboutView path="/about" />
      </GroupPage>
    </Router>
  );
};

export default App;

And in the outer GroupPage component I need to use the :groupId parameter:

const GroupPage: React.FC<RouteComponentProps> = ({ children }) => {
  debugger;
  const params = useParams();
  const groupId = params.groupId as string;

  // query an API using groupId and store it in a context to be 
  // accessible to other nested components (such as AboutView and PostsView)

When I go to /g/123, which renders the PostsView, it works fine and I receive the groupId of 123 inside GroupPage, however when I go to /g/123/about the groupId is lost and params is null (still when using useParams inside GroupPage).

If I move the useParams from the GroupPage into the nested AboutView, then I can receive the params and groupId from /g/123/about but this is frustrating because I don't want to have to repeat the logic for multiple nested components and would rather have it in the outer GroupPage component (which needs the groupId to query an API for group related data and then I use a context to make it available for those nested components).

Am I doing something wrong and is there a way to achieve what I need? Thank you.


Solution

  • I figured out that I can use useMatch with a wildcard instead to achieve this:

    const GroupPage: React.FC<RouteComponentProps> = ({ children }) => {
      debugger;
      const match = useMatch("/g/:groupId/*");
      const groupId = match?.groupId as string;
    

    documentation: https://reach.tech/router/api/useMatch

    This always returns the groupId for both the PostsView and AboutView routes.

    Unless anyone knows of a better way, we can consider this question resolved :)