Skip to content

fix(react-db): idiomatic useLiveQuery & useLiveSuspenseQuery hooks - #1721

Open
zeorin wants to merge 1 commit into
TanStack:mainfrom
zeorin:feat/idiomatic-react-hooks
Open

fix(react-db): idiomatic useLiveQuery & useLiveSuspenseQuery hooks#1721
zeorin wants to merge 1 commit into
TanStack:mainfrom
zeorin:feat/idiomatic-react-hooks

Conversation

@zeorin

@zeorin zeorin commented Aug 12, 2026

Copy link
Copy Markdown

🎯 Changes

These hooks where using refs to track previous versions of certain variables, and reading those during render, which is an anti-pattern that breaks the Rules of Hooks and may lead to subtle bugs, especially in concurrent mode.

Using state instead is more idiomatic and ensures there will be no state tearing, even during concurrent mode updates.

I discovered this while trying to work around an issue where an error thrown by the queryFn in QueryCollection would lead to infinite retries, and eventually, the browser running out of memory.

TODO: I haven't yet checked or adjusted the following hooks:

  • useLiveInfiniteQuery
  • useLiveQueryEffect
  • usePacedMutations

✅ Checklist

  • I have tested this code locally with pnpm test. There are failing tests, but they were not introduced by my changes.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • Bug Fixes
    • Improved live query state handling for more reliable updates during concurrent rendering.
    • Fixed collection changes and Suspense readiness transitions to update consistently.
    • Improved promise reuse during Suspense preloading.
    • Stabilized live query subscriptions and returned results to reduce unnecessary updates.
    • Improved consistency when live query inputs change, helping prevent stale or mismatched results.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 65dc9dad-a4ac-4d82-9a71-856789ad8974

📥 Commits

Reviewing files that changed from the base of the PR and between 5582d36 and 66ed096.

📒 Files selected for processing (1)
  • packages/react-db/src/useLiveQuery.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/react-db/src/useLiveQuery.ts

📝 Walkthrough

Walkthrough

useLiveQuery and useLiveSuspenseQuery replace ref-based tracking with React state. The hooks update collection handling, observer subscriptions, Suspense promise caching, readiness tracking, and result memoization.

Changes

React live-query hooks

Layer / File(s) Summary
Live query state and observer lifecycle
packages/react-db/src/useLiveQuery.ts, .changeset/eleven-gifts-shine.md
useLiveQuery stores collection, dependency, and configuration values in state. It recreates observers when collections change and uses memoized callbacks with useSyncExternalStore. The changeset documents the patch.
Suspense readiness and promise handling
packages/react-db/src/useLiveSuspenseQuery.ts
useLiveSuspenseQuery stores collection and readiness in state, caches rejection-safe preload promises in a WeakMap, and memoizes the returned result.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Mergeability Score: ⚪ Minimal · up to 66ed0

The PR replaces ref-based version tracking with state in two published React hooks and includes a changeset. No actionable merge-blocking risk remains; it is merge-ready after normal checks and review.

Possibly related PRs

  • TanStack/db#1642: This PR also changes ref-based live-query tracking in useLiveQuery.ts.
  • TanStack/db#1675: This PR addresses related React live-query state and subscription handling.
  • TanStack/db#1699: This PR modifies analogous useLiveQuery and useLiveSuspenseQuery implementations.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description check ✅ Passed The description includes the required changes, testing, and release impact sections, with a changeset and test status documented.
Title check ✅ Passed The title clearly identifies the two hooks updated and accurately summarizes the main React hook implementation change.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@zeorin
zeorin force-pushed the feat/idiomatic-react-hooks branch from a9de250 to 5f23973 Compare August 12, 2026 19:59
@zeorin
zeorin marked this pull request as ready for review August 12, 2026 20:01

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@packages/react-db/src/useLiveQuery.ts`:
- Around line 335-340: The needsNewCollection condition should not use
!collection as its initialization check, because disabled queries may
intentionally leave collection null and repeatedly update state. In the relevant
useLiveQuery logic, use prevDeps === null for initialization while preserving
the existing config and dependency-change checks.

In `@packages/react-db/src/useLiveSuspenseQuery.ts`:
- Around line 190-193: Guard the ready-state update in the useLiveSuspenseQuery
flow by calling setHasBeenReady(true) only when collectionStatus is ready and
hasBeenReady is false, preventing repeated render-phase state updates while
preserving the existing ready-state behavior.
🪄 Autofix

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8779cc43-0926-4a80-a890-cde7642f1fab

📥 Commits

Reviewing files that changed from the base of the PR and between dc53f0e and 5f23973.

📒 Files selected for processing (3)
  • .changeset/eleven-gifts-shine.md
  • packages/react-db/src/useLiveQuery.ts
  • packages/react-db/src/useLiveSuspenseQuery.ts

Comment thread packages/react-db/src/useLiveQuery.ts Outdated
Comment thread packages/react-db/src/useLiveSuspenseQuery.ts
@zeorin
zeorin force-pushed the feat/idiomatic-react-hooks branch from 5f23973 to 5582d36 Compare August 12, 2026 21:40
These hooks where using refs to track previous versions of certain
variables, and reading those during render, which is an anti-pattern
that breaks the Rules of Hooks and may lead to subtle bugs, especially
in concurrent mode.

Using state instead is more idiomatic and ensures there will be no state
tearing, even during concurrent mode updates.
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