react-router
react-router copied to clipboard
[Bug]: CompatRoute does not match on wildcard paths
What version of React Router are you using?
Steps to Reproduce
Test Case: https://codesandbox.io/s/nifty-curie-be2on9?file=/src/App.js
- In a transitional v5/v6 environment:
- Export a
Dashboardcomponent. - Export a
NotFoundcomponent. - Set up a
CompatRoutewith a catch-all path (uses asterisk) and a control path, e.g./dashboard. Point the former to theNotFoundcomponent and the latter to theDashboardcomponent.<BrowserRouter> <CompatRouter> <Switch> <CompatRoute path="/dashboard" component={Dashboard} /> <CompatRoute path="*" component={NotFound} /> </Switch> </CompatRouter> </BrowserRouter> - Navigate to the control path to verify that routing works at all.
- Navigate to a nonexistent path.
Expected Behavior
- The
Dashboardcomponent renders at/dashboard - The
NotFoundcomponent renders at any other route, e.g./bad-route
Actual Behavior
- The
Dashboardcomponent renders at/dashboard - The
NotFoundcomponent does not render for any route. A blank page is displayed instead
Notes
If you use a v5 Route instead of a CompatRoute, the expected behavior is exhibited.
This bug is caused by https://github.com/remix-run/react-router/blob/4d915e3305df5b01f51abdeb1c01bf442453522e/packages/react-router-dom-v5-compat/lib/components.tsx#L18 The V6 path for <CompatRoute path="*" component={NotFound} /> becomes
*/* which doesn't match anything in v6.
We ended up creating our own version of CompatRoute that doesn't have this issue. It also fixes another but that the official CompatRoute has where it doesn't work with nested V5 routes inside <Switch>.
This CompatRoute solves both the splat route, and nested routes bugs by separating the v5 and v6 path props.
import type { RouteProps } from 'react-router-dom';
import { Route as RouteV5 } from 'react-router-dom';
import { Route as RouteV6, Routes } from 'react-router-dom-v5-compat';
type Props = RouteProps & {
pathV6: string;
};
/**
* Compatibility Route component to help us migrate from `react-router-dom` v5 to
* v6. It renders a V5 route inside of a V6 route.
*
* It takes an intersection type of V5 RouteProps and a pathV6 prop.
*/
export function XCompatRoute({ pathV6, ...rest }: Props): JSX.Element {
return (
<Routes location={rest.location}>
<RouteV6 path={pathV6} element={<RouteV5 {...rest} />} />
</Routes>
);
}
Then you can do
<XCompatRoute path="*" pathV6="*" component={NotFound} />
and if you need nested routes:
// scoped under /foo route
<XCompatRoute path="/foo/bar" pathV6="bar" component={Component} />
Just change your route to this and it works:
<CompatRoute path="*" exact component={NotFound} />
If someone wants to make a PR for wildcard-only routes, that's something we can see about fixing.
This issue has been automatically marked stale because we haven't received a response from the original author in a while 🙈. This automation helps keep the issue tracker clean from issues that are not actionable. Please reach out if you have more information for us or you think this issue shouldn't be closed! 🙂 If you don't do so within 7 days, this issue will be automatically closed.
This issue has been automatically closed because we didn't hear anything from the original author after the previous notice.