React Router v6: Optional Route Parameters – Decision Pending on Native Support
0 reputation · 25 May 2020, 07:02 UTC
0 reputation · 25 May 2020, 07:02 UTC
Implement routes that accept an optional parameter (e.g., /users/:id?) while maintaining predictable matching behavior in React Router v6.
React Router v6 removed Switch and introduced Routes, which uses strict matching. Optional parameters are not natively supported; developers must either split the route into two (/users and /users/:id) or craft a regex pattern. This increases boilerplate and can lead to unexpected 404s if order is not carefully managed.
The core question is whether React Router will add native optional‑parameter syntax in a future release. Until then, the community must choose between workarounds and accept the trade‑offs.
29775 reputation · 25 May 2020, 12:11 UTC
React Router v6 does not expose a native optional‑parameter syntax (e.g. /users/:id?). The maintainers have not announced a plan to add this feature in the upcoming v7 release, and the current design continues to rely on strict path matching where the most specific route wins regardless of definition order.
At the time of writing, the v7 roadmap does not list optional parameters as a feature. The community can file an issue or contribute, but there is no confirmed implementation date. Until then, developers must use workarounds.
To keep route duplication to a minimum while preserving clear precedence, the most robust approach is to define a single base route and a child route that captures the optional segment. If you do not need a nested layout, a simple route duplication is also acceptable because the strict scoring algorithm will automatically pick the more specific match.
{/* Base path – shows all users */}
} />
{/* Optional id – shows a specific user */}
} />
When a useParams() hook is used inside UserPage, the id will be undefined for /users and a string for /users/42. This pattern keeps the component logic simple and avoids accidental 404s because the more specific route (/users/:id) will always win.
If your route may contain an arbitrary number of optional segments, a splat (*) can capture the rest of the path. The captured value can then be parsed manually.
} />
Inside UserPage, you can split the params["*"]. string to obtain any optional parts. Be careful to place the splat at the end of the path to avoid greedy matching of unintended segments.
<Route> declarations does not affect matching.useParams() returns a defined value before using it. This prevents runtime errors when the optional param is absent.path="*") after all specific routes to show a 404 page, ensuring that any unmatched URL is handled gracefully.Do you currently nest routes under an <Outlet /> (for shared layout or authentication)? If so, a parent route for /users and a child route for /users/:id may be preferable to keep layout logic separated.
Use comments to ask for clarification. Post a solution as an answer.
29,775 reputation · 25 May 2020, 15:55 UTC
While splitting routes into /users and /users/:id is the standard workaround, it is important to highlight how this interacts with the v6 ranked matching algorithm. Unlike v5's Switch, which matched routes linearly, v6 assigns a score based on specificity.
Because /users/:id is more specific than /users, the router will prioritize the parameterized route whenever an ID is present, regardless of the order in which they are defined in your code. This removes the risk of a "greedy" base route intercepting requests meant for the ID route.
To ensure your component handles both states correctly, verify that your useParams() logic accounts for the parameter being undefined. A common pitfall is assuming the parameter will be an empty string; in v6, if the base route matches, the key for the parameter will simply be absent from the returned object.