diff --git a/.changeset/tidy-books-wave.md b/.changeset/tidy-books-wave.md new file mode 100644 index 00000000..07b7944c --- /dev/null +++ b/.changeset/tidy-books-wave.md @@ -0,0 +1,5 @@ +--- +"@solidjs/router": patch +--- + +Fixes browser history navigation when Forward is pressed while a Back transition is waiting on route data. diff --git a/src/routing.ts b/src/routing.ts index 52c19fd9..eb20bb06 100644 --- a/src/routing.ts +++ b/src/routing.ts @@ -485,7 +485,8 @@ export function createRouterContext( // Transition the location to a new value const transition = (newIntent: Intent, newTarget: LocationChange) => { - if (newTarget.value === reference() && newTarget.state === state()) return; + const currentTarget = lastTransitionTarget || { value: reference(), state: state() }; + if (newTarget.value === currentTarget.value && newTarget.state === currentTarget.state) return; if (lastTransitionTarget === undefined) setIsRouting(true); diff --git a/test/back-forward-pending.spec.tsx b/test/back-forward-pending.spec.tsx new file mode 100644 index 00000000..03ca67a1 --- /dev/null +++ b/test/back-forward-pending.spec.tsx @@ -0,0 +1,62 @@ +// @vitest-environment jsdom +import { createResource, Suspense } from "solid-js"; +import { render } from "solid-js/web"; +import { MemoryRouter, Route, createMemoryHistory } from "../src/index.jsx"; + +const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); + +describe("pending browser history navigation", () => { + test("Forward replaces a pending Back transition to a slow route", async () => { + let resolveSlow!: (value: string) => void; + let slowStarted = 0; + const Slow = () => { + const [value] = createResource(() => { + slowStarted++; + return new Promise(resolve => { + resolveSlow = resolve; + }); + }); + return Slow {value()}; + }; + const history = createMemoryHistory(); + history.set({ value: "/", scroll: false }); + history.set({ value: "/slow", scroll: false }); + history.set({ value: "/fast", scroll: false }); + const root = document.createElement("div"); + const dispose = render( + () => ( + ( + <> +

{props.location.pathname}

+ Loading}>{props.children} + + )} + > + Home} /> + + Fast} /> +
+ ), + root + ); + + try { + await wait(10); + expect(root.textContent).toContain("Fast"); + history.back(); + await wait(10); + expect(slowStarted).toBe(1); + history.forward(); + await wait(10); + resolveSlow("loaded"); + await wait(25); + expect(history.get()).toBe("/fast"); + expect(root.querySelector("#location")?.textContent).toBe("/fast"); + expect(root.textContent).toContain("Fast"); + } finally { + dispose(); + } + }); +});