From b541b8dd5a582b1e95a2fd0111eeac2ab92f738b Mon Sep 17 00:00:00 2001
From: Matt Brophy
Date: Tue, 16 Jan 2024 12:42:32 -0500
Subject: [PATCH] Fix NavLink isPending with a basename (#11195)
---
.changeset/brave-pillows-juggle.md | 5 +++
.../__tests__/nav-link-active-test.tsx | 40 +++++++++++++++++++
packages/react-router-dom/index.tsx | 7 +++-
3 files changed, 51 insertions(+), 1 deletion(-)
create mode 100644 .changeset/brave-pillows-juggle.md
diff --git a/.changeset/brave-pillows-juggle.md b/.changeset/brave-pillows-juggle.md
new file mode 100644
index 0000000000..82820194fd
--- /dev/null
+++ b/.changeset/brave-pillows-juggle.md
@@ -0,0 +1,5 @@
+---
+"react-router-dom": patch
+---
+
+Fix `NavLink` `isPending` when a `basename` is used
diff --git a/packages/react-router-dom/__tests__/nav-link-active-test.tsx b/packages/react-router-dom/__tests__/nav-link-active-test.tsx
index f6ba739be1..f437f83f0c 100644
--- a/packages/react-router-dom/__tests__/nav-link-active-test.tsx
+++ b/packages/react-router-dom/__tests__/nav-link-active-test.tsx
@@ -942,6 +942,46 @@ describe("NavLink using a data router", () => {
expect(screen.getByText("Link to Bar").className).toBe("");
expect(screen.getByText("Link to Baz").className).toBe("active");
});
+
+ it("applies the default 'active'/'pending' classNames when a basename is used", async () => {
+ let dfd = createDeferred();
+ let router = createBrowserRouter(
+ createRoutesFromElements(
+ }>
+ Foo page
} />
+ dfd.promise}
+ element={Bar page
}
+ />
+
+ ),
+ {
+ window: getWindow("/base/foo"),
+ basename: "/base",
+ }
+ );
+ render();
+
+ function Layout() {
+ return (
+ <>
+ Link to Foo
+ Link to Bar
+
+ >
+ );
+ }
+
+ expect(screen.getByText("Link to Bar").className).toBe("");
+
+ fireEvent.click(screen.getByText("Link to Bar"));
+ expect(screen.getByText("Link to Bar").className).toBe("pending");
+
+ dfd.resolve(null);
+ await waitFor(() => screen.getByText("Bar page"));
+ expect(screen.getByText("Link to Bar").className).toBe("active");
+ });
});
describe("NavLink under a Routes with a basename", () => {
diff --git a/packages/react-router-dom/index.tsx b/packages/react-router-dom/index.tsx
index 9a6ab99f72..532658706e 100644
--- a/packages/react-router-dom/index.tsx
+++ b/packages/react-router-dom/index.tsx
@@ -1028,7 +1028,7 @@ export const NavLink = React.forwardRef(
let path = useResolvedPath(to, { relative: rest.relative });
let location = useLocation();
let routerState = React.useContext(DataRouterStateContext);
- let { navigator } = React.useContext(NavigationContext);
+ let { navigator, basename } = React.useContext(NavigationContext);
let isTransitioning =
routerState != null &&
// Conditional usage is OK here because the usage of a data router is static
@@ -1053,6 +1053,11 @@ export const NavLink = React.forwardRef(
toPathname = toPathname.toLowerCase();
}
+ if (nextLocationPathname && basename) {
+ nextLocationPathname =
+ stripBasename(nextLocationPathname, basename) || nextLocationPathname;
+ }
+
// If the `to` has a trailing slash, look at that exact spot. Otherwise,
// we're looking for a slash _after_ what's in `to`. For example:
//