Skip to content

Stabilize fresh React Suspense requests - #16

Merged
ConsoleTVs merged 5 commits into
mainfrom
fix/react-fresh-suspense
Oct 24, 2026
Merged

ConsoleTVs merged 5 commits into
mainfrom
fix/react-fresh-suspense

Conversation

@ConsoleTVs

@ConsoleTVs ConsoleTVs commented Oct 24, 2026 •

Copy link
Copy Markdown
Member

Summary

fresh render read
  select instance-owned request by key
  reuse across Suspense retries and fresh siblings
  retain after commit
  release after last consumer unmounts

Evidence

  • Before: React DOM regression made two requests before the first delayed fetch resolved, with no user input (npx vitest run src/react/hooks/useQueryFresh.test.tsx -t 'shares per-hook').
    After: 113 tests pass across 15 files, including 24 tests added relative to current main's 89 tests. Regression coverage includes retries, siblings, rerenders, StrictMode, key/instance changes, remounts, errors, and explicit refreshes.
  • Targeted integration: 52 tests pass across resource, mutation-ordering, request-ownership, fresh React, background-error, and broadcast-provider suites. Added cases cover ordered mutations surviving obsolete completion; hydration/resource synchronization with abort/replacement ownership; and fresh provider context retaining caller channel ownership through cleanup.
  • npm test, npm run lint, npm run format:check, git diff --check, and sensitive-path checks pass. The final follow-up commit changes documentation only and passes lint/format checks.
  • npm run build exits 0 and emits bundles, but reports the existing Solid QueryProvider.tsx:80 TS2786 diagnostic. Reproduced on unchanged current-main baseline ad27cc6; baseline passes 89 tests and prints the same negative-timeout warning category.
  • Root npx tsc --build --pretty false remains blocked by baseline React/Solid JSX pollution: 75 diagnostics on current main, 76 here (the additional use-site is the new test rendering the existing QueryProvider). Isolated React/core typechecking has zero diagnostics across 36 root files, including all new tests.
  • Initial npm ci reported 16 dependency vulnerabilities. This PR does not change dependencies relative to main.

Merge Danger

Door: two-way

Fresh React reads now share a request lifetime instead of restarting on every render. Uncommitted/rejected selections remain until invalidation or instance collection. Committed consumers retain their successful value through failed refreshes; initial render errors and explicit action rejections retain their existing behavior.

Hand-written Query adapters require migration to implement resource; createQuery callers need no API migration. The breaking-change footer can trigger another major release after main's v2.0.0. Main integration conflicts are resolved; await review/CI before merging.

Hydration updates cache/resource state immediately. The existing async refetch transition can defer the visible update while a request remains pending; this was independently reproduced on unchanged main and is not changed by this fix. Integration tests assert immediate cache/resource synchronization and final rendered state after observers settle.

Blast Radius: consumers

The per-instance resource API synchronizes successful writes only after ownership/supersession checks. Existing imperative query(..., { fresh: true }) still aborts/replaces pending requests. Providers neither create nor close channels. No force push, rebase, reset, or PR merge was performed.

Own fresh render requests within each query instance and retain them across retries and sibling consumers. Keep imperative fresh queries independent and document request lifetimes and invalidation.

BREAKING CHANGE: Hand-written implementations of Query must now implement resource(). Implement the documented retain/release request lifecycle or obtain instances from createQuery(); createQuery callers need no API migration. This instance-owned lifecycle is required because React discards initial hook state when rendering suspends.
Preserve request ownership and background observer error handling while synchronizing fresh resource cache writes. Add integration coverage for obsolete request rejection and fresh refresh failure/recovery.
@ConsoleTVs
ConsoleTVs marked this pull request as ready for review October 24, 2026 12:30
Keep queued mutation commits and fetch supersession while synchronizing fresh resource promises. Preserve opt-in broadcast ownership and both migration guides; cover mutation, hydration, abort and provider integration.
@ConsoleTVs
ConsoleTVs merged commit 32104b1 into main Oct 24, 2026
6 checks passed
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.

1 participant