Skip to content

Commit

Permalink
Do not short circuit loaders on initial load when hash is present
Browse files Browse the repository at this point in the history
  • Loading branch information
brophdawg11 committed May 15, 2023
1 parent 4ccdc11 commit 9d88448
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/initialize-with-hash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@remix-run/router": patch
---

Fix bug where initial data load would not kick off when hash is present
51 changes: 50 additions & 1 deletion packages/router/__tests__/router-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1476,14 +1476,22 @@ describe("a router", () => {
});
});

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

it("does not run loaders on hash change only navigations (hash -> new hash)", async () => {
let t = initializeTmTest({ url: "/#foo" });
expect(t.router.state.loaderData).toMatchObject({ root: "ROOT" });
let A = await t.navigate("/#bar");
expect(A.loaders.root.stub.mock.calls.length).toBe(0);
expect(t.router.state.loaderData).toMatchObject({ root: "ROOT" });
});

it("does not run loaders on same-hash navigations", async () => {
let t = initializeTmTest({ url: "/#bar" });
expect(t.router.state.loaderData).toMatchObject({ root: "ROOT" });
Expand Down Expand Up @@ -5245,6 +5253,47 @@ describe("a router", () => {
router.dispose();
});

it("kicks off initial data load when hash is present", async () => {
let loaderDfd = createDeferred();
let loaderSpy = jest.fn(() => loaderDfd.promise);
let router = createRouter({
history: createMemoryHistory({ initialEntries: ["/#hash"] }),
routes: [
{
path: "/",
loader: loaderSpy,
},
],
});
router.initialize();

expect(console.warn).not.toHaveBeenCalled();
expect(loaderSpy.mock.calls.length).toBe(1);
expect(router.state).toMatchObject({
historyAction: "POP",
location: expect.objectContaining({ pathname: "/", hash: "#hash" }),
initialized: false,
navigation: {
state: "loading",
location: { pathname: "/", hash: "#hash" },
},
});
expect(router.state.loaderData).toEqual({});

await loaderDfd.resolve("DATA");
expect(router.state).toMatchObject({
historyAction: "POP",
location: expect.objectContaining({ pathname: "/", hash: "#hash" }),
initialized: true,
navigation: IDLE_NAVIGATION,
loaderData: {
"0": "DATA",
},
});

router.dispose();
});

it("executes loaders on push navigations", async () => {
let t = setup({
routes: TASK_ROUTES,
Expand Down
13 changes: 9 additions & 4 deletions packages/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1225,10 +1225,13 @@ export function createRouter(init: RouterInit): Router {
return;
}

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

if (a.hash === "") {
// No hash -> hash
// /page -> /page#hash
return b.hash !== "";
} else if (a.hash === b.hash) {
// current hash -> same hash
// /page#hash -> /page#hash
return true;
} else if (b.hash !== "") {
// current hash -> new hash
// /page#hash -> /page#other
return true;
}

// If the hash is removed the browser will re-perform a request to the server
// /page#hash -> /page
return false;
}

Expand Down

0 comments on commit 9d88448

Please sign in to comment.