React. Cannot get URL params with useParams() in nested component

I have a simple demo application where you can view quotes individually (QuoteDetail) and view comments under them. I need the url parameters in both components, but I can only get them in the parent component.

App.tsx:

<Switch>
  // ...
  <Route path="/quotes" exact>
    <AllQuotes />
  </Route>
  <Route path="/quotes/:quoteId">
    <QuoteDetail />
  </Route>
  // ...
</Switch>

QuoteDetail.tsx:

export interface QuoteDetailParams {
  quoteId: string;
}

const QuoteDetail: React.FC<QuoteDetailProps> = (props) => {
  const match = useRouteMatch();
  const { quoteId } = useParams<QuoteDetailParams>();
  // ...

  console.log(quoteId); // <-- THIS ONE WORKS      
  // ...

  return (
    <React.Fragment>
      {quote}
      <Route path={match.path} exact>
        <div className="centered">
          <Link className="btn--flat" to={`${match.url}/comments`}>
            Show Comments
          </Link>
        </div>
      </Route>
      <Route path={`${match.url}/comments`} exact>
        <div className="centered">
          <Link className="btn--flat" to={`/quotes/${quoteId}`}>
            Hide Comments
          </Link>
        </div>
        <Comments />
      </Route>
    </React.Fragment>
  );
};

As you can see, when I click a button to load comments, the url changes from /quotes/1/ to /quotes/1/comments which should load the Comments component as well. However, in Comments.tsx, I can't access the url parameter.

Comments.tsx:

const Comments = () => {
  const params = useParams<QuoteDetailParams>();
  const { quoteId } = params;
  // ...

  console.log(params); <-- THIS ONE RETURNS undefined

  // ...

  return (
    <section className={classes.comments}>
      <h2>User Comments</h2>
      {comments}
    </section>
  );
};

I have no idea what I'm doing wrong here. Of course, I can pass the parameter using a component prop as well, but this is not desired in my case. Help is appreciated.

I'm using [email protected]


match

  • match.url is the portion of the URL, it's useful for building nested <Link>s.
  • match.path is the path pattern used to patch, it's useful for building nested <Route>s.

Your QuoteDetail component is using match.url for building the nested route when it should use match.path.

<Route path={`${match.url}/comments`} exact> // <-- incorrect route path
  ...
</Route>

It should be:

<Route path={`${match.path}/comments`} exact>
  ...
</Route>