react-router icon indicating copy to clipboard operation
react-router copied to clipboard

[Feature]: Optional routing parameters in v6

Open vocko opened this issue 4 years ago • 9 comments

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

In the previous versions, we could specify optional parameters using the ? character in the end of the name. This has been dropped due to the removal of the regular expressions support. As I can understand the reasoning behind the added complexity from regular expressions, I believe this particular feature was very useful and it should be doable using just string functions.

Why should this feature be included?

At the moment if there are multiple paths for the same element, you have to register all of them separately. Imagine element dashboard that can take plenty of optional parameters.

In the v5 we could specify pathlike this:

<Route path="/dashboard/:param1?/:param2?/:param3?/:param4?">
    <Dashboard />
</Route>

And /dashboard, /dashboard/1, ..., /dashboard/1/2/3/4 were all valid routes.

In v6, we have to register each route separately:

<Route path="dashboard" element={<Dashboard />} />
<Route path="dashboard/:param1" element={<Dashboard />} />
<Route path="dashboard/:param1/:param2" element={<Dashboard />} />
<Route path="dashboard/:param1/:param2/:param3" element={<Dashboard />} />
<Route path="dashboard/:param1/:param2/:param3/:param4" element={<Dashboard />} />

This is unnecessarily verbose.

If there is any better solution under the new version, I would like to hear about it, I might have missed something as I have only upgraded to v6 recently.

vocko avatar Nov 23 '21 07:11 vocko

I have realised that this is a sub-query of https://github.com/remix-run/react-router/issues/8254. If it gets answered/resolved there, this issue can be closed. However, I still believe, regardless of the regex path resolution (moved to a separated library, as suggested, is imho the best solution), optional parameters should be a part of the base router logic.

vocko avatar Nov 24 '21 00:11 vocko

I agree. In the upgrade guide I was caught off guard, because while I did skim and understand that the advanced regex support has been removed, I expected that this ‘core’ functionality had been left alone. Like @vocko, I see this trailing ? as something you parse using simple string functions and not something that would be affected by removing advanced regex support.

Haraldson avatar Dec 08 '21 14:12 Haraldson

I for one would love to see RegEx support brought back. Related: https://github.com/remix-run/react-router/issues/7285

bluepeter avatar Dec 11 '21 17:12 bluepeter

Removing regex was a mistake. Whatever survey you did about "usecases", it clearly wasn't broad enough.

"Just write a <Route> for every single possible match!" is an absurd response.

cha0s avatar Mar 16 '22 03:03 cha0s

I solve this problem like that:

function List() {
  const match1 = useMatch("/items/:id");
  const match2 = useMatch("/items/:id/:tab");

  const id = match1?.params?.id;
  const tab = match2?.params?.tab;
}

<Route path="/items/*" element={<List/>} />

But, it's not good, anywhere.

kulakowka avatar Mar 16 '22 08:03 kulakowka

I'm just doing

useParams().varThatUsedToMatch = 'whatever';

In a root component. This must be what they intended, right? :^)

cha0s avatar Mar 16 '22 16:03 cha0s

@mjackson please 🙏

pkasarda avatar Apr 02 '22 16:04 pkasarda

I solve this problem like that:

function List() {
  const match1 = useMatch("/items/:id");
  const match2 = useMatch("/items/:id/:tab");

  const id = match1?.params?.id;
  const tab = match2?.params?.tab;
}

<Route path="/items/*" element={<List/>} />

But, it's not good, anywhere.

Thanks @kulakowka - this was how I ended up having to migrate some of my routes with optional params. The only thing I had to do was make sure that the first match had a wildcard at the end, so that the second parameter could be included without causing it to not match:

  const match1 = useMatch("/items/:id/*");

mikegoatly avatar Apr 20 '22 21:04 mikegoatly

I've done

<Route path="dashboard" element={<Dashboard />}>
    <Route path="dashboard/:param1" />
    <Route path="dashboard/:param1/:param2" />
    <Route path="dashboard/:param1/:param2/:param3" />
    <Route path="dashboard/:param1/:param2/:param3/:param4" />
  </Route>

Which works but gets the warning

Matched leaf route at location "/dashboard/5" does not have an element. This means it will render an <Outlet /> with a null value by default resulting in an "empty" page.

But the Dashboard is rendered rom the parent and it has access to all params so it works :)

Gyran avatar Apr 28 '22 13:04 Gyran

This is now superseded by #9546

timdorr avatar Nov 02 '22 23:11 timdorr