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: update createHref to be history-aware #9409

Merged
merged 10 commits into from Oct 17, 2022
1 change: 1 addition & 0 deletions contributors.yml
Expand Up @@ -19,6 +19,7 @@
- chensokheng
- chrisngobanh
- christopherchudzicki
- codeape2
- coryhouse
- cvbuelow
- david-crespo
Expand Down
81 changes: 80 additions & 1 deletion packages/react-router-dom/__tests__/link-href-test.tsx
@@ -1,6 +1,17 @@
import * as React from "react";
import {
BrowserRouter,
HashRouter,
Link,
MemoryRouter,
Outlet,
Route,
RouterProvider,
Routes,
createBrowserRouter,
createHashRouter,
} from "react-router-dom";
import * as TestRenderer from "react-test-renderer";
import { MemoryRouter, Routes, Route, Link, Outlet } from "react-router-dom";

describe("<Link> href", () => {
describe("in a static route", () => {
Expand Down Expand Up @@ -679,4 +690,72 @@ describe("<Link> href", () => {
);
});
});

describe("when using a browser router", () => {
it("renders proper <a href> for BrowserRouter", () => {
let renderer: TestRenderer.ReactTestRenderer;
TestRenderer.act(() => {
renderer = TestRenderer.create(
<BrowserRouter>
<Routes>
<Route path="/" element={<Link to="/path?search=value#hash" />} />
</Routes>
</BrowserRouter>
);
});
expect(renderer.root.findByType("a").props.href).toEqual(
"/path?search=value#hash"
);
});

it("renders proper <a href> for createBrowserRouter", () => {
let renderer: TestRenderer.ReactTestRenderer;
TestRenderer.act(() => {
let router = createBrowserRouter([
{
path: "/",
element: <Link to="/path?search=value#hash">Link</Link>,
},
]);
renderer = TestRenderer.create(<RouterProvider router={router} />);
});
expect(renderer.root.findByType("a").props.href).toEqual(
"/path?search=value#hash"
);
});
});

describe("when using a hash router", () => {
it("renders proper <a href> for HashRouter", () => {
let renderer: TestRenderer.ReactTestRenderer;
TestRenderer.act(() => {
renderer = TestRenderer.create(
<HashRouter>
<Routes>
<Route path="/" element={<Link to="/path?search=value#hash" />} />
</Routes>
</HashRouter>
);
});
expect(renderer.root.findByType("a").props.href).toEqual(
"#/path?search=value#hash"
);
});

it("renders proper <a href> for createHashRouter", () => {
let renderer: TestRenderer.ReactTestRenderer;
TestRenderer.act(() => {
let router = createHashRouter([
{
path: "/",
element: <Link to="/path?search=value#hash">Link</Link>,
},
]);
renderer = TestRenderer.create(<RouterProvider router={router} />);
});
expect(renderer.root.findByType("a").props.href).toEqual(
"#/path?search=value#hash"
);
});
});
});
4 changes: 3 additions & 1 deletion packages/router/router.ts
Expand Up @@ -1739,7 +1739,9 @@ export function createRouter(init: RouterInit): Router {
navigate,
fetch,
revalidate,
createHref,
// Passthrough to history-aware createHref used by useHref so we get proper
// hash-aware URLs in DOM paths
createHref: (to: To) => init.history.createHref(to),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was just an oversight. We have a local createHref brought over from transition manager that creates a "server" URL without the hash, but the one we want to expose is the history-aware version so that hash routers properly generate <a href="#/path> links

getFetcher,
deleteFetcher,
dispose,
Expand Down