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 NavLink isPending with a basename #11195

Merged
merged 1 commit into from
Jan 16, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/brave-pillows-juggle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"react-router-dom": patch
---

Fix `NavLink` `isPending` when a `basename` is used
40 changes: 40 additions & 0 deletions packages/react-router-dom/__tests__/nav-link-active-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(
<Route path="/" element={<Layout />}>
<Route path="foo" element={<p>Foo page</p>} />
<Route
path="bar"
loader={() => dfd.promise}
element={<p>Bar page</p>}
/>
</Route>
),
{
window: getWindow("/base/foo"),
basename: "/base",
}
);
render(<RouterProvider router={router} />);

function Layout() {
return (
<>
<NavLink to="/foo">Link to Foo</NavLink>
<NavLink to="/bar">Link to Bar</NavLink>
<Outlet />
</>
);
}

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", () => {
Expand Down
7 changes: 6 additions & 1 deletion packages/react-router-dom/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1028,7 +1028,7 @@ export const NavLink = React.forwardRef<HTMLAnchorElement, NavLinkProps>(
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
Expand All @@ -1053,6 +1053,11 @@ export const NavLink = React.forwardRef<HTMLAnchorElement, NavLinkProps>(
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:
//
Expand Down