Skip to content

Commit 0b89da3

Browse files
authored
Do not short circuit loaders on initial load when hash is present (#10493)
1 parent e665a46 commit 0b89da3

File tree

3 files changed

+64
-5
lines changed

3 files changed

+64
-5
lines changed

.changeset/initialize-with-hash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@remix-run/router": patch
3+
---
4+
5+
Fix bug where initial data load would not kick off when hash is present

packages/router/__tests__/router-test.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1476,14 +1476,22 @@ describe("a router", () => {
14761476
});
14771477
});
14781478

1479-
it("does not run loaders on hash change only navigations", async () => {
1479+
it("does not run loaders on hash change only navigations (no hash -> hash)", async () => {
14801480
let t = initializeTmTest();
14811481
expect(t.router.state.loaderData).toMatchObject({ root: "ROOT" });
14821482
let A = await t.navigate("/#bar");
14831483
expect(A.loaders.root.stub.mock.calls.length).toBe(0);
14841484
expect(t.router.state.loaderData).toMatchObject({ root: "ROOT" });
14851485
});
14861486

1487+
it("does not run loaders on hash change only navigations (hash -> new hash)", async () => {
1488+
let t = initializeTmTest({ url: "/#foo" });
1489+
expect(t.router.state.loaderData).toMatchObject({ root: "ROOT" });
1490+
let A = await t.navigate("/#bar");
1491+
expect(A.loaders.root.stub.mock.calls.length).toBe(0);
1492+
expect(t.router.state.loaderData).toMatchObject({ root: "ROOT" });
1493+
});
1494+
14871495
it("does not run loaders on same-hash navigations", async () => {
14881496
let t = initializeTmTest({ url: "/#bar" });
14891497
expect(t.router.state.loaderData).toMatchObject({ root: "ROOT" });
@@ -5245,6 +5253,47 @@ describe("a router", () => {
52455253
router.dispose();
52465254
});
52475255

5256+
it("kicks off initial data load when hash is present", async () => {
5257+
let loaderDfd = createDeferred();
5258+
let loaderSpy = jest.fn(() => loaderDfd.promise);
5259+
let router = createRouter({
5260+
history: createMemoryHistory({ initialEntries: ["/#hash"] }),
5261+
routes: [
5262+
{
5263+
path: "/",
5264+
loader: loaderSpy,
5265+
},
5266+
],
5267+
});
5268+
router.initialize();
5269+
5270+
expect(console.warn).not.toHaveBeenCalled();
5271+
expect(loaderSpy.mock.calls.length).toBe(1);
5272+
expect(router.state).toMatchObject({
5273+
historyAction: "POP",
5274+
location: expect.objectContaining({ pathname: "/", hash: "#hash" }),
5275+
initialized: false,
5276+
navigation: {
5277+
state: "loading",
5278+
location: { pathname: "/", hash: "#hash" },
5279+
},
5280+
});
5281+
expect(router.state.loaderData).toEqual({});
5282+
5283+
await loaderDfd.resolve("DATA");
5284+
expect(router.state).toMatchObject({
5285+
historyAction: "POP",
5286+
location: expect.objectContaining({ pathname: "/", hash: "#hash" }),
5287+
initialized: true,
5288+
navigation: IDLE_NAVIGATION,
5289+
loaderData: {
5290+
"0": "DATA",
5291+
},
5292+
});
5293+
5294+
router.dispose();
5295+
});
5296+
52485297
it("executes loaders on push navigations", async () => {
52495298
let t = setup({
52505299
routes: TASK_ROUTES,

packages/router/router.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,10 +1225,13 @@ export function createRouter(init: RouterInit): Router {
12251225
return;
12261226
}
12271227

1228-
// Short circuit if it's only a hash change and not a mutation submission
1228+
// Short circuit if it's only a hash change and not a mutation submission.
1229+
// Ignore on initial page loads because since the initial load will always
1230+
// be "same hash".
12291231
// For example, on /page#hash and submit a <Form method="post"> which will
12301232
// default to a navigation to /page
12311233
if (
1234+
state.initialized &&
12321235
isHashChangeOnly(state.location, location) &&
12331236
!(opts && opts.submission && isMutationMethod(opts.submission.formMethod))
12341237
) {
@@ -4015,16 +4018,18 @@ function isHashChangeOnly(a: Location, b: Location): boolean {
40154018
}
40164019

40174020
if (a.hash === "") {
4018-
// No hash -> hash
4021+
// /page -> /page#hash
40194022
return b.hash !== "";
40204023
} else if (a.hash === b.hash) {
4021-
// current hash -> same hash
4024+
// /page#hash -> /page#hash
40224025
return true;
40234026
} else if (b.hash !== "") {
4024-
// current hash -> new hash
4027+
// /page#hash -> /page#other
40254028
return true;
40264029
}
40274030

4031+
// If the hash is removed the browser will re-perform a request to the server
4032+
// /page#hash -> /page
40284033
return false;
40294034
}
40304035

0 commit comments

Comments
 (0)