invalidateQueries should preserve refetch intent during initial fetch
I maintainer di solito rispondono entro 1 giorno
Valutazione
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Idoneità per principianti
- 35/100
- Tipo di issue
- Funzionalità
- Chiarezza
- Da chiarire
- Stato di attività
- Attiva
- Stack tecnologico
- typescript
- Ambito
- api, backend-api-design
Direzione di ricerca
Inizia tracciando queryClient.invalidateQueries durante un fetch iniziale e rivedi la discussione precedente in #8530. Definisci test per invalidazioni ripetute, il comportamento del refetch finale e la cancellazione, quindi determina come specificare una policy globale e un override per chiamata; il lavoro è completo quando l’intento di invalidazione non viene perso e il comportamento di latenza scelto è coperto.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
AI-assisted issue: Written in GitHub Copilot, configured to GPT-5.6 Sol Medium, under close supervision of a frontend lead software engineer with 10+ years of experience. I spent roughly a full day reproducing this behavior and working back and forth with AI to understand the implementation, history, trade-offs, and alternatives. I therefore have high personal confidence in the core problem and proposed direction. Some API details may still need refinement, but I believe the substance is worth considering.
Problem
invalidateQueries() can effectively lose its refetch intent when called during an initial fetch.
The query is marked invalid, but the attempted refetch reuses the existing in-flight promise because no cached data exists yet. After that request settles, no trailing refetch occurs.
Data fetched from a server state predating the invalidation can therefore become the settled cache value indefinitely.
This was previously discussed in #8530. That discussion focused primarily on whether the initial request should be cancelled. I think cancellation and invalidation intent should be treated separately:
- Cancellation determines how quickly the client reaches any usable state versus the final state.
- Invalidation means the current result is no longer trusted and should eventually cause a fetch started after invalidation.
Real-world impact
We encountered this with a long-running data-check query:
- Query starts while server data is in state A.
- User changes server data to state B before query finishes.
- Mutation succeeds and invalidates the data-check query.
- Because the query is still performing its initial fetch, invalidation reuses that request.
- Original request returns a result based on state A.
- UI settles on that result even though backend is now in state B.
From user perspective, successful change appears not to have worked. UI contradicts current backend state solely because of request timing.
A loading indicator does not solve this. Loading ends when original request completes, but stale result remains cached without a subsequent request.
Expected invariant
Invalidation should be durable intent:
A fetch that started before an invalidation should not permanently satisfy that invalidation.
This does not necessarily mean initial fetch must be cancelled. Two useful strategies exist.
Strategy 1: first usable state sooner
Allow current fetch to complete, then perform one trailing refetch:
fetch A starts
invalidate
invalidate
fetch A completes and provides first usable state
fetch B starts once
fetch B completes with current state
Multiple invalidations should coalesce into one trailing refetch.
Benefits:
- Same time-to-first-result as current behavior.
- Avoids extending initial loading state.
- Eventually converges to data fetched after invalidation.
- Fits stale-while-revalidate behavior well.
This seems like a reasonable default.
Strategy 2: final state sooner
Cancel current fetch and immediately start a replacement:
fetch A starts
invalidate
fetch A is cancelled
fetch B starts immediately
fetch B completes with current state
Benefits:
- Reaches current final state sooner.
- Never commits known-outdated result.
- Useful for status indicators and other correctness-sensitive queries.
Trade-off: user waits longer for any usable result.
Proposed API direction
Expose this as a global/defaultable query-client policy, with per-call override:
new QueryClient({
defaultOptions: {
queries: {
invalidationBehavior: 'queue',
},
},
})
queryClient.invalidateQueries(filters, {
invalidationBehavior: 'cancel',
})
Exact option and value names need design work. Names should communicate the latency choice:
- Prioritize first usable state, then revalidate.
- Prioritize final post-invalidation state.
- Preserve current behavior, where the in-flight initial result is accepted without trailing work.
I do not have a good concise name for the third behavior yet. reuse and deduplicate describe implementation details rather than the freshness consequence.
I would avoid adding a none value here. refetchType: 'none' already represents mark-stale-without-refetch behavior.
Why both invariant and option matter
Automatically scheduling a trailing refetch fixes lost invalidation, but only provides the first-usable-state-sooner strategy.
Some applications need final-state-as-soon-as-possible behavior. They should not need to manually coordinate cancelQueries() followed by invalidateQueries() at every call site.
A global policy plus per-call override provides both:
- Safe eventual-freshness default.
- Explicit low-latency path to final state.
- No ignored invalidation intent.
- Lingua principale
- TypeScript
- Stelle
- 50.4k
- Fork
- 4.2k
- Merge medio
- 11h 33m
- PR unite (30g)
- 421
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di TanStack/query
-
solid-query: STRICT_READ_UNTRACKED on Solid 2 — client()/options() read in component body (useMutation, useBaseQuery)Forse di nuovo libera Una pull request per questa issue è stata chiusa senza essere unita. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
TanStack/query#11358 · 2 commenti · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
solid-query: switching the queryClient accessor strands the new client's cache (subscription stays on the old observer)Forse già presa @MaNaN1803 l’ha presa 74 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
TanStack/query#11106 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 45/100
I maintainer di solito rispondono entro 1 giorno
-
setQueryData: NoInfer loses discriminated-union members when spreading a narrowed updater valueForse già presa @iosayin l’ha presa 1 giorno fa. Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 55/100
I maintainer di solito rispondono entro 1 giorno
-
setQueryData updater loses discriminated-union fields when spreading inferred NoInfer dataForse già presa @boriskozak l’ha presa 1 giorno fa. Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 68/100
TanStack/query#11794 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di TanStack/query
Issue simili
-
perf(core): getComments() runs the approved count and the comment list as two sequential queriesApertaarea/core bot:bug bot:working
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
emdash-cms/emdash#3905 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 90/100
lingdojo/kana-dojo#31728 · 1 commento · 5 reazioni ·
I maintainer di solito rispondono entro 1 giorno
-
selective-claw: freshTailTurns=0 keeps ALL turns verbatim and summarizes none (slice(-0) === slice(0))Forse già presa @zjncs l’ha presa oggi. Apertacomponent:tokenless
Difficoltà 2/5 1-3 ore Idoneità per principianti 80/100
agentic-os-org/ANOLISA#6112 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
bug needs triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
rjsf-team/react-jsonschema-form#5439 ·
I maintainer di solito rispondono entro 1 giorno
-
enhancement
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
I maintainer di solito rispondono entro 1 giorno