[svelte-query] A result key first read after the query settled stays stale: the component's copy refreshes only on a change of an already-tracked key

Offen
#12,485 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

@lazerg arbeitet bereits daran.

Seit 01.11.2026.

  • #12487 von @lazerg — offen

Bewertung

Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Anfängerfreundlichkeit
20/100
Issue-Typ
Bug
Klarheit
Klar beschrieben
Aktivitätsstatus
Veraltet
Tech-Stack
typescript
Bereich
frontend

Rechercherichtung

Start with observer.trackResult(result) in createBaseQuery.svelte.js around line 29, then the #trackedProps check in queryObserver.js around lines 395-403, and the onPropTracked hook. Check the linked pull request #12487 first, since it already targets this bug. Done means the minimal case shows a b after about 300 ms, with a test that reads a key for the first time after the query has settled.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

Versions: @tanstack/svelte-query 6.3.1, @tanstack/query-core 5.104.1, Svelte 5.

What happens

When notifyOnChangeProps is unset, createBaseQuery wraps the result in observer.trackResult(result) (createBaseQuery.svelte.js:29). QueryObserver.updateResult then notifies only when a key in #trackedProps changes (queryObserver.js:395-403).

The observer does add a key to its tracked set when a template first reads it. But the component's reactive copy is updated only through those notifications. If a query settles while the template has read only some of its keys, the update is skipped and the component keeps its copy of the old result. A key that the template reads later is then read from that stale copy, and nothing updates it again, because the query has already settled.

Minimal case

<script lang="ts">
  import { createQuery } from '@tanstack/svelte-query';

  const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
  const a = createQuery(() => ({ queryKey: ['a'], queryFn: () => wait(300).then(() => 'a') }));
  const b = createQuery(() => ({ queryKey: ['b'], queryFn: () => Promise.resolve('b') }));
</script>

{#if a.isError || b.isError}
  <p>error</p>
{:else if a.data === undefined || b.data === undefined}
  <p>loading</p>
{:else}
  <p>{a.data} {b.data}</p>
{/if}

Expected: a b after about 300 ms.

Actual: loading stays forever. b settles first, while the template has read only b.isError, because the || short-circuits before b.data. The change to b.data doesn't notify, so the component's copy of b keeps data: undefined. When a settles, the template reads b.data from that stale copy.

Workaround

Set notifyOnChangeProps: 'all' in the client's default query options, or read every key before branching.

Suggestion

Pass onPropTracked to trackResult and refresh the component's copy when a key is first tracked, or skip tracking in the Svelte adapter, since Svelte already re-renders key by key.

Vorherrschende Sprache
TypeScript
Sterne
50.5k
Forks
4.2k
Ø Merge
11 Std. 2 Min.
Gemergte PRs (30 T.)
524

Entwicklungsumgebung

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus TanStack/query

Alle Issues in TanStack/query

Ähnliche Issues

Weitere Issues zu TypeScript

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.