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 />} />
[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 />} />
[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.
path is now also only a string, so you can't even use an array of paths to match, you have to be very explicit.path prop of the Route component if I'm not mistaken. If you are doing some "manual" matching then I believe you need to be explicit with the paths, i.e. test for "/base/:detail" and "/base" separately.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.
basePath += `${params[i]}/`;. This way you can call the function regardless of depth.Use wildcard:
<Route path="/cart/*" component={<CartPage />} />
* when destructiong the result of useParams() and rename it, it would look somthing like this const { '*': myOptionalParameter} = useParams(), however this will not be helpful if you have multiple optional parameters in your routeBase 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 (
// ...
);
}
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"