Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: relative navigation from index routes #8697

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions contributors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,5 @@
- underager
- vijaypushkin
- vikingviolinist
- KutnerUri
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove KutnerUri which is already in here above - likely a merge conflict issue

- JaffParker
4 changes: 2 additions & 2 deletions packages/react-router-dom-v5-compat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export type {
Pathname,
Search,
RoutesProps,
} from "./react-router-dom";
} from "../react-router-dom";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to update these paths - they need to point to the local copy of ./react-router-dom which is put there during the build - the reasoning is explained in the comment above these exports

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually - I see your note about the failing tests now. That may just be because you hadn't run yarn build locally which copies these files into place. I think you can just git revert 71e8b7f to undo the pathing changes here, then yarn build && yarn test and see if that fixes it 👍

export {
BrowserRouter,
HashRouter,
Expand Down Expand Up @@ -108,7 +108,7 @@ export {
useResolvedPath,
useRoutes,
useSearchParams,
} from "./react-router-dom";
} from "../react-router-dom";

export type { StaticRouterProps } from "./lib/components";
export { CompatRouter, CompatRoute, StaticRouter } from "./lib/components";
2 changes: 1 addition & 1 deletion packages/react-router-dom-v5-compat/lib/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useHistory, Route as RouteV5 } from "react-router-dom";
// We are a wrapper around react-router-dom v6, so bring it in
// and bundle it because an app can't have two versions of
// react-router-dom in its package.json.
import { Router, Routes, Route } from "../react-router-dom";
import { Router, Routes, Route } from "../../react-router-dom";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here - need to use the local copy of react-router-dom


// v5 isn't in TypeScript, they'll also lose the @types/react-router with this
// but not worried about that for now.
Expand Down
45 changes: 45 additions & 0 deletions packages/react-router/__tests__/navigate-test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from "react";
import * as TestRenderer from "react-test-renderer";
import { MemoryRouter, Navigate, Routes, Route } from "react-router";
import { Outlet } from "../lib/components";

describe("<Navigate>", () => {
describe("with an absolute href", () => {
Expand Down Expand Up @@ -45,5 +46,49 @@ describe("<Navigate>", () => {
</h1>
`);
});

it("skips a level from an index route", () => {
let renderer: TestRenderer.ReactTestRenderer;
TestRenderer.act(() => {
renderer = TestRenderer.create(
<MemoryRouter initialEntries={["/home"]}>
<Routes>
<Route path="home">
<Route index element={<Navigate to="../about" />} />
</Route>
<Route path="about" element={<h1>About</h1>} />
</Routes>
</MemoryRouter>
);
});

expect(renderer.toJSON()).toMatchInlineSnapshot(`
<h1>
About
</h1>
`);
});

it("skips a level from a layout route", () => {
let renderer: TestRenderer.ReactTestRenderer;
TestRenderer.act(() => {
renderer = TestRenderer.create(
<MemoryRouter initialEntries={["/home"]}>
<Routes>
<Route element={<Outlet />}>
<Route path="home" element={<Navigate to="../about" />} />
</Route>
<Route path="about" element={<h1>About</h1>} />
</Routes>
</MemoryRouter>
);
});

expect(renderer.toJSON()).toMatchInlineSnapshot(`
<h1>
About
</h1>
`);
});
});
});
6 changes: 4 additions & 2 deletions packages/react-router/lib/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ export function useNavigate(): NavigateFunction {
let routePathnamesJson = JSON.stringify(
matches.map((match) => match.pathnameBase)
);
let isPathlessRoute = !!matches[matches.length - 1]?.route.index;

let activeRef = React.useRef(false);
React.useEffect(() => {
Expand All @@ -182,7 +183,8 @@ export function useNavigate(): NavigateFunction {
let path = resolveTo(
to,
JSON.parse(routePathnamesJson),
locationPathname
locationPathname,
isPathlessRoute
);

if (basename !== "/") {
Expand All @@ -195,7 +197,7 @@ export function useNavigate(): NavigateFunction {
options
);
},
[basename, navigator, routePathnamesJson, locationPathname]
[routePathnamesJson, locationPathname, isPathlessRoute, basename, navigator]
);

return navigate;
Expand Down
7 changes: 5 additions & 2 deletions packages/router/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,8 @@ function resolvePathname(relativePath: string, fromPathname: string): string {
export function resolveTo(
toArg: To,
routePathnames: string[],
locationPathname: string
locationPathname: string,
isPathlessRoute = false
): Path {
let to = typeof toArg === "string" ? parsePath(toArg) : { ...toArg };
let toPathname = toArg === "" || to.pathname === "" ? "/" : to.pathname;
Expand All @@ -672,7 +673,9 @@ export function resolveTo(
if (toPathname == null) {
from = locationPathname;
} else {
let routePathnameIndex = routePathnames.length - 1;
let routePathnameIndex = isPathlessRoute
? routePathnames.length - 2
: routePathnames.length - 1;

if (toPathname.startsWith("..")) {
let toSegments = toPathname.split("/");
Expand Down