ShadowLeaf
ShadowLeaf

Reputation: 473

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 />} />

Upvotes: 47

Views: 36129

Answers (6)

Drew Reese
Drew Reese

Reputation: 202721

[email protected]+

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

[email protected]

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.

Upvotes: 70

import * as React from 'react';
import {useNavigate} from "react-router-dom"

function App() {
  const location = useNavigate();

  React.useEffect(() => {
    ga('send', 'pageview');
    location("/route");

  }, [location]);

  return (
    // ...
  );
}

this is not working because it is not supported in version 6 in react router dom you must use import {useNavigate} from "react-router-dom"

Upvotes: 0

shahiq
shahiq

Reputation: 31

It would be great if this could be described in the migration guide – or if there was at least a hint. So the recommended way of doing "optional" params really is ...

<Route path='/page/:friendlyName/:sort' element={<Page/>} />
<Route path='/page/:friendlyName/' element={<Page/>} />

Upvotes: 3

Federico
Federico

Reputation: 5778

Base react router doc

https://reactrouter.com/docs/en/v6/hooks/use-location

would not this work?

import * as React from 'react';
import { useLocation } from 'react-router-dom';

function App() {
  let location = useLocation();

  React.useEffect(() => {
    ga('send', 'pageview');
  }, [location]);

  return (
    // ...
  );
}

Upvotes: 0

Kernel James
Kernel James

Reputation: 4064

Use wildcard:

<Route path="/cart/*" component={<CartPage />} />

Upvotes: 5

Vočko
Vočko

Reputation: 2986

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.

Upvotes: 7

Related Questions