Skip to content

[Feature]: Bring back routeProps or more specifically match<Params> in a render prop #9560

@fbarbare

Description

@fbarbare

What is the new or updated feature that you are suggesting?

Allowing the children of the Route component to be a function/render prop and pass in the match object

const BlogPost = ({ id }: { id: string }) => {
  return <div>BlogPost {id}</div>
}

export const Routes = () => {
  <Route path={'/blog-posts/:blogPostId' as const}>
    {(match) => <BlogPost id={match.params.blogPostId} />}
  </Route>
}

Why should this feature be included?

In previous versions of react-router we were able to use a render prop on the Route component to render our pages/components when matching the given path and this render prop was given a routeProps argument. I agree that most of the props in this routeProps were not very useful as we could just use the hooks/HOC to get them, but the match object was very useful and informative as it allowed us to keep the path/params logic in the routes. The TypeScript inferance that we had on top of that was amazing, it allowed us to have strongly typed params in the path and pass them down as props to the rendered components rather than rely on the "unreliable" useParams.

This implementation here uses react-router@5. Passing the path prop as a const allowed us to be 100% sure we had the blogPostId param and that we were passing this down declaratively to our BlogPost:

const BlogPost = ({ id }: { id: string }) => {
  return <div>BlogPost {id}</div>
}

export const Routes = () => {
  <Route
    path={'/blog-posts/:blogPostId' as const}
    render={({ match }) => (
      <BlogPost id={match.params.blogPostId} />
    )}
  />
}

image

With the react-router@6 way we have to trust that the BlogPost component is actually rendered under a Route that has the blogPostId param in its path. We are passing a generic to the useParam hook and essentially saying: give me whatever param you have from the URL but just cast it to what I think is there, might not be though.

const BlogPost = () => {
  const { blogPostId } = useParams<{ blogPostId: string }>()
  return <div>BlogPost {blogPostId}</div>
}

export const Routes = () => {
  <Route path={'/blog-posts/:blogPostId' as const}>
    <BlogPost />
  </Route>
}

Funny enough I had made mistake in the react-router@6 example at the start as I had written it like this, which TypeScript is fine with but id does not actually exist in the params, it should be blogPostId:

const BlogPost = () => {
  const { id } = useParams<{ id: string }>()
  return <div>BlogPost {id}</div>
}

export const Routes = () => {
  <Route path={'/blog-posts/:blogPostId' as const}>
    <BlogPost />
  </Route>
}

Thank you for considering this!

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature-requestUsed to close PRs that haven't gone through/been accepted the Proposal process yet

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions