Question

Alternate way for optional parameters in v6

In v5, we could add trailing ? to route for optional parameters, but as in v6, the support for the same has been dropped, so what's the alternate way of writing the following piece of code?

<Route path="/cart/:id?" component={<CartPage />} />

 46  34429  46
1 Jan 1970

Solution

 69

react-router-dom@6.5.0+

Optional segments/parameters have been re-introduced to the library. The docs have been updated, but v6.5.0 Release Notes include the details as well.

The above routes can be merged to a single route:

<Route path="/cart/:id?" element={<CartPage />} />

Edit alternate-way-for-optional-parameters-in-v6

react-router-dom@6-6.4.5

After quite a bit of digging through the source code to understand how path parsing was different in RRDv6 from RRDv5, and turned up nothing really other than they no longer use path-to-regex, I hit up the repo's issues section and found this issue which outright states they don't plan to support optional path parameters in v6.

See FAQ: What Happened to Regexp Routes Paths?

It seems the suggested solution is to render 2 routes to match either path and render the same component.

Example:

<Route path="/cart/:id" element={<CartPage />} />
<Route path="/cart/" element={<CartPage />} />

or

<Route path="/cart">
  <Route index element={<CartPage />} />
  <Route path=":id" element={<CartPage />} />
</Route>

The latter is really only syntactic sugar around relative paths from "/cart" though.

2021-11-17

Solution

 7

As Drew Reese said, there is no support for the optional parameters in v6 (at least as of now).

I have ended up writing these little helper functions that register all nested routes for the optional parameters.

const registerOptionalParamRoute = (optionalParams: string[], element: Element) => {
    if (optionalParams.length === 0)
        return <Fragment/>;

    const param = optionalParams[0];
    optionalParams.splice(0, 1);

    return <Route path={param} element={element}>
        {registerOptionalParamRoute(optionalParams, element)}
    </Route>;
};

const registerOptionalParams = (path: string, element: JSX.Element) => {
    const params = path.split("/");
    let basePath = "";
    let optionalParams = [];

    for (let i = 0; i < params.length; i++) {
        if (params[i] === '')
            continue;
      
        if (!params[i].includes("?"))
            basePath += "/" + params[i];
        else
            optionalParams.push(params[i].substr(0, params[i].length - 1));
    }

    return <Route path={basePath} key={basePath} element={element}>
        {registerOptionalParamRoute(optionalParams, element)}
    </Route>;
};

Then call it:

<Routes>
    {registerOptionalParams('/component/:param1?/:param2?', <Component/>)}
</Routes>    

For an example url /component/:param1?/:param2? and given component <Component/> it generates the following jsx element:

<Route path="component" element={<Component/>}>
    <Route path=":param1" element={<Component/>}>
        <Route path=":param2" element={<Component/>} />
    </Route>
</Route>

I have also created feature request for optional parameters (https://github.com/remix-run/react-router/issues/8381), will see what feedback it will get.

2021-11-24