Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useRoutePaths #9755

Merged
merged 9 commits into from
Dec 27, 2023
Merged

useRoutePaths #9755

merged 9 commits into from
Dec 27, 2023

Conversation

Tobbe
Copy link
Member

@Tobbe Tobbe commented Dec 26, 2023

Users are requesting more introspection possibilities for the router.
This PR adds two hooks to get the path declared in the router for a given route.
You can use useRoutePaths() to get a map of all route names to their literal routes (e.g. { editPost: '/posts/{id:Int}/edit', post: '/posts/{id:Int}' }).
Or you can use useRoutePath('editPost') to get the path of a single route by its name

Copy/paste from the docs updates:

useRoutePaths

useRoutePaths() is a React hook you can use to get a map of all routes mapped to their literal paths, as they're defined in your routes file.

Example usage:

const routePaths = useRoutePaths()

return <pre><code>{JSON.stringify(routePaths, undefined, 2)}</code></pre>

Example output:

{
  "home": "/"
  "about": "/about",
  "login": "/login",
  "signup": "/signup",
  "forgotPassword": "/forgot-password",
  "resetPassword": "/reset-password",
  "newContact": "/contacts/new",
  "editContact": "/contacts/{id:Int}/edit",
  "contact": "/contacts/{id:Int}",
  "contacts": "/contacts",
}

useRoutePath

This is a convenience hook for when you only want the path for a single route.

const aboutPath = useRoutePath('about') // returns "/about"

is the same as

const routePaths = useRoutePaths()
const aboutPath = routePaths.about // Also returns "/about"

@Tobbe Tobbe marked this pull request as draft December 26, 2023 14:30
@Tobbe Tobbe changed the title useRoutePaths [RFC]: useRoutePaths Dec 26, 2023
@Tobbe Tobbe added the release:feature This PR introduces a new feature label Dec 26, 2023
@Tobbe Tobbe added this to the next-release milestone Dec 26, 2023
@Tobbe Tobbe mentioned this pull request Dec 26, 2023
@Tobbe Tobbe marked this pull request as ready for review December 27, 2023 22:17
@Tobbe Tobbe merged commit f3e1c37 into redwoodjs:main Dec 27, 2023
32 checks passed
@Tobbe Tobbe changed the title [RFC]: useRoutePaths useRoutePaths Dec 27, 2023
dac09 added a commit to dac09/redwood that referenced this pull request Dec 28, 2023
…p-prebuild

* 'main' of github.com:redwoodjs/redwood: (1608 commits)
  Docker: Update to work with corepack and yarn v4 (redwoodjs#9764)
  [RFC]: useRoutePaths (redwoodjs#9755)
  Adds a note about the two commands you will use with your schema to the top of the schema file (redwoodjs#8589)
  docs: Supertokens.md: Fix typo (redwoodjs#9765)
  Fix supertokens docs & integration issues (redwoodjs#9757)
  fix(apollo): Enhance error differently for Suspense Cells (redwoodjs#9640)
  SSR smoke-test: Use <Metadata /> (redwoodjs#9763)
  chore(deps): update dependency @types/qs to v6.9.11 (redwoodjs#9761)
  chore(ci): Better error handling in detectChanges.mjs (redwoodjs#9762)
  fix(path-alias): Fix aliasing of paths using ts/jsconfig (redwoodjs#9574)
  chore(deps): update dependency @types/yargs to v17.0.32 (redwoodjs#9759)
  Make it easier to find useMatch docs (redwoodjs#9756)
  chore(unit tests): Use side-effect import to fix TS errors (redwoodjs#9754)
  fix(context): Refactor context (redwoodjs#9371)
  docs: Replaced deprecated <Set private> with PrivateSet within router.md (redwoodjs#9749)
  add TS support for storybook preview tsx config extension (redwoodjs#9309)
  fix(studio): Fix windows path issues (redwoodjs#9752)
  chore(tasks): Add comparison view to nmHoisting visualisation (redwoodjs#9751)
  chore(cli): make fs modules used in the CLI consistent (redwoodjs#9746)
  ...
jtoar pushed a commit that referenced this pull request Jan 3, 2024
Make it possible to specify route param values that need to match.

If this is your route: `<Route path="/blog/{year}/{month}/{day}"
page={BlogPostPage} name="blogPost" />`
And you want to only match posts from 2001 you can now do this:

`useMatch('/blog/{year}/{month}/{day}', { routeParams: { year: '2001' }
})`

This is **finally** a solution to matching route paths. The work started
in #7469, but we were never able to come up with an api/dx that we
really liked. This PR and #9755 together however provides a solution
that we're much more happy with, and that also supports the use case
outlined in that original PR.

Here's the example from #7469 as it could be solved with the code in
this PR

```jsx
const Navbar () => {
  const { project } = useParams()
  const routePaths = useRoutePaths()

  const modes = [
    {
      name: "Info",
      route: routes.info({ project }),
      match: useMatch(routePaths.info), // using the hook together with routePaths
    },
    {
      name: "Compare",
      route: routes.compare({ project, id: "1" }),
      match: useMatch(useRoutePath('compare')), // alternative to the above
    },
    // ...
  ]

  return (
    <>
      {modes.map((x) => <Button as={Link} to={x.route} isActive={x.match} />)}
    </>
  )
}
```

And, as described at the top of this description, we can also be more
specific than in that example if needed. Like if we only wanted to match
a specific project on the "Compare" route we could do this:

```jsx
  const modes = [
    {
      name: "Info",
      route: routes.info({ project }),
      match: useMatch(routePaths.info),
    },
    {
      name: "Compare against Alpha",
      route: routes.compare({ project, id: "1" }),
      match: useMatch(useRoutePath('compare'), { routeParams: { project: 'alpha' } }),
    },
    {
      name: "Compare against Beta",
      route: routes.compare({ project, id: "1" }),
      match: useMatch(useRoutePath('compare'), { routeParams: { project: 'beta' } }),
    },
    // ...
  ]
```

Here's another example

```jsx
<Route path="/{dynamic}/{path}" page={ExamplePage} name="example" />

const exampleRoutePath = useRoutePath('example')
// => '/{dynamic}/{path}'

const matchOnlyDog = useMatch(exampleRoutePath, { routeParams: { dynamic: 'dog' }})
const matchFullyDynamic = useMatch(exampleRoutePath)
```

In the above example, if the current page url was
`https://example.org/dog/fido` then both `matchOnlyDog` and
`matchFullyDynamic` would have `match: true`.
If the current page instead was `https://example.org/cat/garfield` then
only `matchFullyDynamic` would match

(This PR replaces #9774)
@jtoar jtoar modified the milestones: next-release, v7.0.0 Jan 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release:feature This PR introduces a new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants