Repository navigation
Conversation
`refetch()`, `refetchQueries()`, `invalidateQueries()` and `resetQueries()` took a running stream over and settled with its current value: the `queryFn` never ran again, and `resetQueries()` left the query as it was. A regular query cancels the fetch in progress and runs its `queryFn` again. Live queries now do the same: the running stream stops, a new one starts, and the refetch settles with its first value, right away for a stream that emits its current value when subscribed. Automatic refetches (window focus, reconnection, mount, `refetchInterval`) still join the running stream, as they join any fetch in progress. A refetch or `cancelQueries()` while the fetch that follows the stream waits for the network now stops the stream too. It kept running before, and the refetch's fetch ended up following it, never settling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FLxad4gLrsk68haFCJrakH
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5284c162e5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
TanStack cancels the fetch in progress on a refetch only when the query has data. Before a live query's first value, `refetch()`, `refetchQueries()` and `invalidateQueries()` therefore join the fetch in progress: the stream keeps running, and they settle with its first value. `resetQueries()` still restarts it. "Forever Query" said every explicit refetch restarts the stream. It now states the exception, and a test pins it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FLxad4gLrsk68haFCJrakH
mbret
added a commit
that referenced
this pull request
Oct 21, 2026
* fix(queries): leave a stopped live query's freshness to staleTime When a live query's stream stopped (its last observer unmounting, `cancelQueries`, the query getting disabled, a fetch of an unused query), the query was also marked stale, so the next observer refetched it whatever its `staleTime`. A regular query keeps its freshness when its fetch is cancelled: `staleTime` alone decides when it refetches. Live queries now do the same. With the default `staleTime`, which the docs recommend for them, nothing changes: the value is stale as soon as the stream stops, so the next observer that needs it reopens the stream. With a longer one, the cached value is shown without a stream until it goes stale, as the docs already warn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FLxad4gLrsk68haFCJrakH * fix(queries): restart a running stream on refetch, like a regular query (#206) * fix(queries): restart a running stream on refetch, like a regular query `refetch()`, `refetchQueries()`, `invalidateQueries()` and `resetQueries()` took a running stream over and settled with its current value: the `queryFn` never ran again, and `resetQueries()` left the query as it was. A regular query cancels the fetch in progress and runs its `queryFn` again. Live queries now do the same: the running stream stops, a new one starts, and the refetch settles with its first value, right away for a stream that emits its current value when subscribed. Automatic refetches (window focus, reconnection, mount, `refetchInterval`) still join the running stream, as they join any fetch in progress. A refetch or `cancelQueries()` while the fetch that follows the stream waits for the network now stops the stream too. It kept running before, and the refetch's fetch ended up following it, never settling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FLxad4gLrsk68haFCJrakH * docs(queries): a refetch before a stream's first value joins its fetch TanStack cancels the fetch in progress on a refetch only when the query has data. Before a live query's first value, `refetch()`, `refetchQueries()` and `invalidateQueries()` therefore join the fetch in progress: the stream keeps running, and they settle with its first value. `resetQueries()` still restarts it. "Forever Query" said every explicit refetch restarts the stream. It now states the exception, and a test pins it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FLxad4gLrsk68haFCJrakH --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #205: please merge that one first. I'll then retarget this PR to
mainand bring it up to date.Summary
refetch(),queryClient.refetchQueries(),queryClient.invalidateQueries()andqueryClient.resetQueries()now restart a running live stream, the way a regular query runs itsqueryFnagain:queryFnruns again and a new stream starts.resetQueries(), which first puts the query back in its initial state.BehaviorSubject, most live database queries). For a stream that only emits on events, it happens at the next event.refetch(),refetchQueries()andinvalidateQueries()join the fetch in progress instead, because TanStack only cancels a fetch for a refetch when the query has data. The stream keeps running, and they settle with its first value.resetQueries()still restarts it.refetchInterval. So doesrefetch({ cancelRefetch: false }).Before, these calls took over the running stream and settled with its current value. The
queryFnnever ran again, andresetQueries()did nothing to a live query.This also fixes a bug with the fetch that follows the stream when it waits for the network (
networkMode: "online"while offline). A refetch orcancelQueries()during that wait now stops the stream. Before, the stream kept running aftercancelQueries(). After a refetch, the refetch's fetch ended up following the old stream once back online, so awaiting the refetch never settled.What changes for consumers
queryFnruns again.queryFn. This includes a mutation whoseonSuccessreturnsinvalidateQueries(): the mutation stays pending until that event.resetQueries()now puts a live query back in its initial state and restarts its stream.Migration:
refetch, userefetch({ cancelRefetch: false }): it joins the running stream and settles when the stream ends.refetch()restarts it.invalidateQueries()inonSuccesswithout returning or awaiting it.Implementation (
createObservableQueryFn)queryFnagain. Only the fetch the bridge starts to follow the stream joins the running stream. The take-over branch is gone.nextguard for a stream that was cancelled but kept is removed, because no such stream exists any more.Tests
queryFnruns again, the old stream is unsubscribed, the data stays until the new stream emits, and the awaited refetch settles at the new stream's first value.refetch()alone restarts the stream now.{ made: 2, open: 1 }.cancelQueriesduring that wait stops the stream.Each new or changed test that pins the restart fails against #205's bridge. The two offline tests also fail without the network-wait handling.
Restarting doesn't change render counts. An invalidation that brings the same value causes 0 renders for a component that reads
data, and 1 for one that also readsisFetching, as before.Checks
npm run checkandnpm run buildpass.npx vitest run --typecheck: 255 tests pass, no type errors.npm run test:ci: 3 runs on the latest commit, all green.useQuery$.invalidation.test.tsx(StrictMode): 12 runs, all green.Release
Like #199, #204 and #205, this is a
fix:commit with noBREAKING CHANGE:footer. It does reverse documented behaviour: the docs said refetching kept a running stream. If you want a major release, add aBREAKING CHANGE:footer when squashing.🤖 Generated with Claude Code
https://claude.ai/code/session_01FLxad4gLrsk68haFCJrakH