Skip to content

fix: Upgrade nuqs to 2.9.2 before the shared table hook lands - #374

Merged
frankieramirez merged 1 commit into
mainfrom
fix/upgrade-nuqs-2-9-2
Jul 28, 2026
Merged

fix: Upgrade nuqs to 2.9.2 before the shared table hook lands#374
frankieramirez merged 1 commit into
mainfrom
fix/upgrade-nuqs-2-9-2

Conversation

@frankieramirez

@frankieramirez frankieramirez commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Resolves #368, unblocking #360 on the useTableState map.

Why

nuqs 2.9.0 and 2.9.1 carry an upstream bug (nuqs#1501) where useQueryState(s) permanently desyncs from the URL after React discards a render. It is fixed in 2.9.2.

This repo was on the affected configuration, not just an affected version: src/App.tsx:10 imports NuqsAdapter from nuqs/adapters/react-router/v7 on React 19, and SeriesTable.tsx is the only nuqs consumer — so the blast radius was the Library page's sort, filter and pagination state.

The fix is three lines in nuqs' own useQueryStates.ts (nuqs#1502): a render-phase recovery when the mirrored internalState drifts from the authoritative stateRef.current.

What changed

frontend/package.json ^2.9.0^2.9.2, and the lockfile follows.

Raising the declared floor rather than only moving the lock is deliberate — it stops a fresh npm install resolving back onto 2.9.0/2.9.1. The only other lockfile movement is nuqs' own dependency @standard-schema/spec 1.0.0 → 1.1.0, which dedupes against the copy vitest already pulled in. No source changes.

Verification

npm run lint clean; npm --prefix frontend test 141/141 across 27 files; production build succeeds.

Beyond that, a manual pass against a production build in Chrome, since the existing tests do not cover the back/forward path. The real database holds one series, so pagination was not exercisable against it; the production build was served behind a throwaway proxy forwarding to the live backend for real auth, overriding only GET /api/series with 63 synthetic rows. Data synthetic; router, adapter, build and browser real.

Step Result
page next ×2, prev rows 20–39 / 40–59 / 20–39, URL in step
sort change while on page=1 ?sort=ComicName.asc, page dropped in the same write
status filter while on page=1 page dropped, sort preserved, only paused rows
search (300ms) while on page=1 ?search=Marvel, page dropped — the mixed 300ms/50ms batch collapses correctly
back/forward across a route change state restored exactly, round-trip stable

history.length never grew, confirming history: "replace" is not being escalated by a batched key.

Notes for the map

  • The research in Is the nuqs shadow-state dance still necessary on nuqs 2.9? #356 was pinned to 2.9.0. I re-checked its load-bearing findings against the installed 2.9.2 dist/ rather than the changelog: the three batching rules are byte-identical and the synchronous emitter.emit is unchanged, so the shared hook's setParams({ sort, page: null }) plan is unaffected. Two findings get stronger — 2.9.1 #1480 makes limitUrlUpdates precedence true in code and not merely in the docs, and #1469 reinforces the single-emitter premise. This also discharges Is the nuqs shadow-state dance still necessary on nuqs 2.9? #356's owed production-build caveat.
  • The pass surfaced a pre-existing defect: a cold load of /library?page=2 renders page 0 and strips page, because the clamp at SeriesTable.tsx:267-276 runs while data is still empty. A/B'd against nuqs@2.9.0 on the same build with the same data — identical wrong result, so it is neither caused nor fixed by this bump. Left untouched here so a regression has one obvious suspect; filed as Decide where the deep-linked-page clamp fix ships #372.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Et1eFmQyJUBncfpsWWvSJC

Summary by CodeRabbit

  • Bug Fixes
    • Improved reliability of URL-backed sorting, filtering, and pagination on the Library page.
    • Prevented state from becoming out of sync with the URL after certain React rendering updates.
  • Chores
    • Updated the underlying URL state handling package to improve React Router compatibility.

nuqs 2.9.0 and 2.9.1 carry an upstream bug (nuqs#1501) where
useQueryState(s) permanently desyncs from the URL after React discards a
render. The repo uses the React Router v7 adapter on React 19 — the
affected configuration — and SeriesTable is the only nuqs consumer, so
the Library page's sort, filter and pagination state was exposed.

2.9.2 fixes it with a three-line render-phase recovery in
useQueryStates. Verified against a production build in Chrome: paging,
sort change, filter change, search, back/forward across a route change,
and a deep-linked reload all keep the rendered table in step with the
URL.

Resolves the ticket "Upgrade nuqs to ^2.9.2 before the shared hook
lands" (#368), unblocking the pagination decision on the useTableState
map (#353).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Et1eFmQyJUBncfpsWWvSJC
@changeset-bot

changeset-bot Bot commented Jul 28, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 31c4136

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
comicarr Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Updates nuqs from ^2.9.0 to ^2.9.2 and adds a patch changeset documenting the React Router URL-state desynchronization fix.

Changes

nuqs dependency upgrade

Layer / File(s) Summary
Dependency upgrade and release metadata
frontend/package.json, .changeset/upgrade-nuqs-to-2-9-2.md
Updates nuqs to ^2.9.2 and records a patch release describing the affected URL-backed state behavior.

Estimated code review effort: 1 (Trivial) | ~2 minutes

Possibly related issues

  • #356 — Addresses the nuqs URL-state desynchronization underlying the SeriesTable shared-state work.

Possibly related PRs

Poem

A bunny hops where query strings flow,
Nuqs gets fixed, two-nine-two in tow.
Sorts and pages keep their place,
Filters follow without a chase.
URL state now stays in grace!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive The nuqs upgrade in package.json matches #368, but the required lockfile update can't be verified because package-lock.json was excluded by path filters. Please include or unfilter frontend/package-lock.json so the lockfile bump to nuqs 2.9.2 can be verified.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately describes the main change: upgrading nuqs to 2.9.2 before the shared table hook work.
Out of Scope Changes check ✅ Passed The diff stays focused on the nuqs upgrade and its changeset note; no unrelated code changes are evident.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/upgrade-nuqs-2-9-2

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/package.json`:
- Line 43: Regenerate frontend/package-lock.json after updating the nuqs
dependency in frontend/package.json, ensuring it reflects the new ^2.9.2
resolution, then include the updated lockfile in the change so npm ci uses the
committed dependency graph.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 67840cda-6fa7-48ee-bbd4-d93f58f1cb66

📥 Commits

Reviewing files that changed from the base of the PR and between ded5b97 and 31c4136.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • .changeset/upgrade-nuqs-to-2-9-2.md
  • frontend/package.json

Comment thread frontend/package.json
@frankieramirez

Copy link
Copy Markdown
Owner Author

@coderabbitai the lockfile is already regenerated and included in this PR — frontend/package-lock.json is one of the three changed files, and it resolves node_modules/nuqs to 2.9.2 (sha512-SUrBU5Pf…) with the root declaration updated to ^2.9.2.

It was produced by npm --prefix frontend install nuqs@^2.9.2, not hand-edited. Independently confirmed by running npm --prefix frontend ci against the committed lockfile, which installed 2.9.2 — so the committed dependency graph is what npm ci uses in CI, and Frontend Lint & Build plus Frontend Tests both pass on it.

No change needed.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@frankieramirez Thanks for the clarification. The committed frontend/package-lock.json is present and pins nuqs to 2.9.2 as required; the reported clean-install and CI verification confirm it is valid. No change is needed.

@frankieramirez
frankieramirez merged commit 979d94c into main Jul 28, 2026
21 checks passed
@frankieramirez
frankieramirez deleted the fix/upgrade-nuqs-2-9-2 branch July 28, 2026 13:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Upgrade nuqs to ^2.9.2 before the shared hook lands

1 participant