Skip to content

Conversation

jaydoshi2
Copy link

@jaydoshi2 jaydoshi2 commented Oct 18, 2025

What?

  • Fixes a bug where Next.js sometimes treats a navigation as a "hash-only" change and skips data fetching when:
    • href (the internal url) has different query/search params between calls, but
    • as contains the same path + hash (e.g. ...#hash).
  • Implementation:
    • onlyAHashChange now accepts an optional url (href) and, when provided, compares the href's pathname+search with the previous asPath so changes in the href's query are considered real navigations.
    • Caller in Router.change() now passes url into onlyAHashChange(...).
  • Tests:
    • Adds an integration test that reproduces the bug and asserts:
      • getInitialProps is re-run when href's query changes even if as contains the same #hash.
      • getInitialProps is not re-run for genuine hash-only changes.

Why?

  • Bug: calling Router.replace(hrefWithQueryAndHash, asWithHash) previously could be considered “only a hash change” if as stayed identical (including #hash), even when href changed its query string. That made the router skip the full navigation/data-fetch flow (so getInitialProps or data fetching wasn't re-run).
  • Fix: include the href (url) in the hash-only check so changes to the href's query/search cause a full navigation/data-fetch as expected.

How?

  • Updated logic in packages/next/src/shared/lib/router/router.ts:
    • onlyAHashChange(as: string, url?: string) — if url is provided, parse it with parseRelativeUrl(url) and use the pathname+search when comparing to previous asPath.
    • In change(), call this.onlyAHashChange(cleanedAs, url) instead of this.onlyAHashChange(cleanedAs).
  • Left scrollToHash behavior unchanged (still uses onlyAHashChange(as) without url), preserving current scroll optimizations for pure hash navigations.

Files changed

  • Modified:
    • packages/next/src/shared/lib/router/router.ts
      • changed onlyAHashChange signature and logic, updated call-site in change().
  • Added integration test:
    • test/integration/router-replace-hash-query/pages/index.js
    • test/integration/router-replace-hash-query/test/index.test.js
    • test/integration/router-replace-hash-query/package.json (empty, placeholder test dir)

Tests added

  • test/integration/router-replace-hash-query/test/index.test.js
    • Uses next-test-utils + next-webdriver to:
      1. Render /.
      2. Ensure the initial page shows test: undefined.
      3. Trigger Router.replace(route + '?test=123#hash', asPath + '#hash').
      4. Confirm the page updates to test: 123 and getInitialProps ran again.
    • Also validates that pure hash-only changes do not trigger getInitialProps.

Checklist for Contributors (please run before opening PR)

  • Run pnpm prettier-fix to fix formatting issues.
  • Add related issues with fixes #<issue> if applicable.
  • Tests added/updated — included integration test in this PR.

Checklist for Maintainers

  • Minimal description added above.
  • Notes about the fix logic are in code comments.
  • Links to issue trackers / Linear: fill in below if necessary.

Closes NEXT-
Fixes #10900 <-- replace with the appropriate issue number if available


How to run the test locally (copy/paste)

  1. Ensure dependencies and build:
# from repo root
pnpm install
# build the project (the repo uses extensive build/test steps; adjust per your workflow)
pnpm -w build

@ijjk
Copy link
Member

ijjk commented Oct 18, 2025

Allow CI Workflow Run

  • approve CI run for commit: e6ab2ec

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

getInitialProps is not running when Router.replace's "href" and "as" contains hash and query params inside "href" change.

2 participants