kruschid / typesafe-routes

Spices up your favorite routing library by adding type safety to plain string-based route definitions.
https://kruschid.github.io/typesafe-routes/
MIT License
102 stars 8 forks source link

How to use `useRouteParams` with nested routes? #32

Closed wongjiahau closed 1 year ago

wongjiahau commented 1 year ago

For example:

import { route } from "typesafe-routes";

const detailsRoute = route("details&:id", { id: stringParser }, {})
const settingsRoute = route("settings", {}, { detailsRoute });
const accountRoute = route("/account", {}, { settingsRoute });

const MyComponent = () => {
  const params = useRouteParams(accountRoute)
  params.id // <- Error: `id` not exists
}
kruschid commented 1 year ago

by design the route fragment that owns that parameter should be passed on to useRouteParams

In your specific case it would work if you change your example to something like this:

const detailsRoutParams = useRouteParams(detailsRoute)
wongjiahau commented 1 year ago

But say accountRoute has an accountId param, which is also required by details route, your code snippet will not work, unless I explicitly add the accountId param to the detailsRoute as well.

kruschid commented 1 year ago

But say accountRoute has an accountId param, which is also required by details route, your code snippet will not work, unless I explicitly add the accountId param to the detailsRoute as well.

That depends. Is :accountId a query param similar to what you have written in your example (&:id, must be prefixed with the &-character)? Then you can access it in any component within the router context. For example:

import { route } from "typesafe-routes";

const detailsRoute = route("details&:id", { id: stringParser }, {})
const settingsRoute = route("settings", {}, { detailsRoute });
const accountRoute = route("/account&:accountId", {}, { settingsRoute });

// details route:
const MyComponent = () => {
  const params = {
    ...useRouteParams(detailsRoute),
    ...useRouteParams(accountRoute),
  }

  params.id // no ts error
  params.accountId // no ts error
}

If :accountId is a dynamic segment (e.g. /account/:accountId) then I think it can't be accessed from the details route component. You could apply prop drilling or context to pass it downn to the details route component.