diff --git a/.changeset/revalidate-with-hash.md b/.changeset/revalidate-with-hash.md new file mode 100644 index 0000000000..f6e317c3a0 --- /dev/null +++ b/.changeset/revalidate-with-hash.md @@ -0,0 +1,5 @@ +--- +"@remix-run/router": patch +--- + +Ensure revalidations happen when hash is present diff --git a/packages/router/__tests__/router-test.ts b/packages/router/__tests__/router-test.ts index 719d6b3508..8a9483db86 100644 --- a/packages/router/__tests__/router-test.ts +++ b/packages/router/__tests__/router-test.ts @@ -7456,6 +7456,49 @@ describe("a router", () => { expect(t.history.replace).not.toHaveBeenCalled(); }); + it("handles revalidation when a hash is present", async () => { + let t = setup({ + routes: TASK_ROUTES, + initialEntries: ["/#hash"], + hydrationData: { + loaderData: { + root: "ROOT_DATA", + index: "INDEX_DATA", + }, + }, + }); + + let key = t.router.state.location.key; + let R = await t.revalidate(); + expect(t.router.state).toMatchObject({ + historyAction: "POP", + location: { pathname: "/" }, + navigation: IDLE_NAVIGATION, + revalidation: "loading", + loaderData: { + root: "ROOT_DATA", + index: "INDEX_DATA", + }, + }); + + await R.loaders.root.resolve("ROOT_DATA*"); + await R.loaders.index.resolve("INDEX_DATA*"); + expect(t.router.state).toMatchObject({ + historyAction: "POP", + location: { pathname: "/" }, + navigation: IDLE_NAVIGATION, + revalidation: "idle", + loaderData: { + root: "ROOT_DATA*", + index: "INDEX_DATA*", + }, + }); + expect(t.router.state.location.hash).toBe('#hash'); + expect(t.router.state.location.key).toBe(key); + expect(t.history.push).not.toHaveBeenCalled(); + expect(t.history.replace).not.toHaveBeenCalled(); + }); + it("handles revalidation interrupted by a navigation", async () => { let t = setup({ routes: TASK_ROUTES, diff --git a/packages/router/router.ts b/packages/router/router.ts index 270afe23c8..1df68e8ebe 100644 --- a/packages/router/router.ts +++ b/packages/router/router.ts @@ -1225,13 +1225,15 @@ 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 revalidation or + // 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
which will - // default to a navigation to /page + // be "same hash". For example, on /page#hash and submit a + // which will default to a navigation to /page if ( state.initialized && + !isRevalidationRequired && isHashChangeOnly(state.location, location) && !(opts && opts.submission && isMutationMethod(opts.submission.formMethod)) ) {