Skip to content

fix(query-core): prevent optimistic fetching when unsubscribedFix/subscribed isfetching#10720

Open
Prasadzoman wants to merge 2 commits into
TanStack:mainfrom
Prasadzoman:fix/subscribed-isfetching
Open

fix(query-core): prevent optimistic fetching when unsubscribedFix/subscribed isfetching#10720
Prasadzoman wants to merge 2 commits into
TanStack:mainfrom
Prasadzoman:fix/subscribed-isfetching

Conversation

@Prasadzoman
Copy link
Copy Markdown

@Prasadzoman Prasadzoman commented May 17, 2026

Problem

When using the subscribed option (common React Native pattern for unfocused screens), isFetching could become true even though:

  • no fetch was running
  • queryFn was not called
  • no observer was attached
  • no query state changed

This resulted in an inconsistent state where:

fetchStatus === 'fetching'
isFetching === true

while the query was actually idle.

Fixes #10718.


Root Cause

QueryObserver.createResult optimistically injected fetchState(...) whenever:

!mounted && shouldFetchOnMount(...)

However, !mounted was true both for:

  • initial optimistic renders before subscription
  • observers that were previously subscribed and later unsubscribed (subscribed: false)

This caused optimistic fetching state to appear even after unsubscribing.


Fix

Adds tracking for whether the observer has ever been subscribed via #everSubscribed.

Optimistic fetch state is now only applied for genuine pre-subscription optimistic renders.

Additionally:

  • updateResult now accepts an optimistic flag
  • getOptimisticResult passes the correct optimistic state
  • #notify skips cache notifications when no listeners exist

Tests

Added regression coverage for:

  • isFetching
  • fetchStatus
  • subscribed: false
  • toggling subscription state

All existing tests pass.

Summary by CodeRabbit

  • Bug Fixes

    • Improved fetch status reporting for unsubscribed queries, now correctly reporting fetchStatus: 'idle' and isFetching: false when appropriate.
  • Refactor

    • Enhanced internal query observer logic to optimize subscription tracking and result creation behavior.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 17, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5819814d-e59c-440f-9215-e3c9a88eac94

📥 Commits

Reviewing files that changed from the base of the PR and between 65b9b72 and 8441110.

📒 Files selected for processing (2)
  • packages/query-core/src/queryObserver.ts
  • packages/react-query/src/__tests__/useQuery.test.tsx

📝 Walkthrough

Walkthrough

This PR fixes a bug where useQuery reports isFetching: true even when no actual fetch is running, caused by unsubscribed observers. The observer now tracks subscription history and computes results differently based on whether it has active listeners, ensuring consistent state reporting.

Changes

Optimistic result behavior for unsubscribed observers

Layer / File(s) Summary
Subscription state tracking
packages/query-core/src/queryObserver.ts
Observer introduces #everSubscribed flag initialized to true on first listener subscription, establishing the subscription history contract.
Optimistic result parameter and determination
packages/query-core/src/queryObserver.ts
createResult now accepts an optimistic boolean parameter (default true); getOptimisticResult derives the optimistic value from #everSubscribed and current listener presence; fetchOnMount only triggers when optimistic && !mounted.
Result update and notification integration
packages/query-core/src/queryObserver.ts
setOptions passes false to updateResult when unmounted; updateResult accepts and forwards the optimistic parameter; #notify only sends cache notifications when hasListeners() is true, and observer state assignments align with optimistic-current logic.
Test validation for unsubscribed state
packages/react-query/src/__tests__/useQuery.test.tsx
New test asserts that unsubscribing a query with no active fetch reports fetchStatus: 'idle' and isFetching: false.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

A rabbit hops through query states,
Tracking subscriptions as they wait,
When listeners vanish, optimism stays,
Yet isFetching falls, no more delays—
Consistency blooms in the fuzzy light! 🐰✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive Title is somewhat garbled with apparent duplication ('Ffix/subscribed isfetching' appears malformed), making it unclear and difficult to parse. Clarify the title to be a clear, single sentence. Example: 'fix(query-core): prevent optimistic fetching when unsubscribed' or 'fix(query-core): fix isFetching state when subscribed false'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed Description is comprehensive and covers the problem, root cause, fix, and tests, but the checklist is not completed (both items unchecked).
Linked Issues check ✅ Passed Code changes directly address the core requirement to prevent optimistic fetching when unsubscribed by introducing #everSubscribed tracking and conditional optimistic state application.
Out of Scope Changes check ✅ Passed Changes are tightly scoped to fixing the unsubscribed isFetching bug: QueryObserver tracking and optimistic-result logic modifications, plus a targeted regression test.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

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.

isFetching becomes true when subscribed=false even though no fetch is running

1 participant