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

[Bug]: CompatRoute does not match on wildcard paths

Open HughxDev opened this issue 3 years ago • 5 comments

What version of React Router are you using?

Steps to Reproduce

Test Case: https://codesandbox.io/s/nifty-curie-be2on9?file=/src/App.js

  1. In a transitional v5/v6 environment:
  2. Export a Dashboard component.
  3. Export a NotFound component.
  4. Set up a CompatRoute with a catch-all path (uses asterisk) and a control path, e.g. /dashboard. Point the former to the NotFound component and the latter to the Dashboard component.
    <BrowserRouter>
      <CompatRouter>
        <Switch>
          <CompatRoute path="/dashboard" component={Dashboard} />
          <CompatRoute path="*" component={NotFound} />
        </Switch>
      </CompatRouter>
    </BrowserRouter>
    
  5. Navigate to the control path to verify that routing works at all.
  6. Navigate to a nonexistent path.

Expected Behavior

  • The Dashboard component renders at /dashboard
  • The NotFound component renders at any other route, e.g. /bad-route

Actual Behavior

  • The Dashboard component renders at /dashboard
  • The NotFound component 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.

HughxDev avatar Nov 05 '22 00:11 HughxDev

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

tryggvigy avatar Nov 15 '22 11:11 tryggvigy

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.

timdorr avatar Nov 15 '22 15:11 timdorr

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.

github-actions[bot] avatar Apr 17 '23 22:04 github-actions[bot]

This issue has been automatically closed because we didn't hear anything from the original author after the previous notice.

github-actions[bot] avatar Apr 24 '23 23:04 github-actions[bot]