useLiveInfiniteQuery commits an empty first render over a synchronously loaded collection (useLiveQuery doesn't)
I maintainer di solito rispondono entro 1 giorno
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 72/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- react, typescript
- Ambito
- frontend
Direzione di ricerca
Start at the useLiveInfiniteQuery hook and compare its collection startup and gcTime behavior with useLiveQuery. Add coverage to the existing hook tests for the synchronous eager-collection reproduction and check StrictMode and abandoned renders. Done means the infinite query has ready data on its first render without leaving sync running for an uncommitted render.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Describe the bug
With an eager, synchronously loaded collection, useLiveInfiniteQuery commits status: idle, data: [] on the first render and only has rows on the second commit. useLiveQuery over the same query with .limit(pageSize) has the rows on its first render.
In our app this shows up as a route that reads "no events" from the first commit and redirects away before the real data lands.
Cause: since #1675 the hook builds its collection with startSync: false ("Synchronization starts only when useSyncExternalStore commits the controller subscription"), so nothing can be published into the first render. useLiveQuery starts sync during render and relies on gcTime to reclaim a collection whose render never commits.
#1894 / #1896 fixed the db side of this for ordered windows over eager sources, so the remaining gap is the React hook only.
To reproduce
import { act, render } from "@testing-library/react"
import { createCollection, localOnlyCollectionOptions } from "@tanstack/db"
import { useLiveInfiniteQuery, useLiveQuery } from "@tanstack/react-db"
const events = createCollection(
localOnlyCollectionOptions({
id: `events`,
getKey: (e: { id: number; n: number }) => e.id,
initialData: Array.from({ length: 20 }, (_, i) => ({ id: i, n: i })),
})
)
const infinite: string[] = []
const plain: string[] = []
function Infinite() {
const r = useLiveInfiniteQuery(
(q) => q.from({ e: events }).orderBy(({ e }) => e.n),
{ pageSize: 10 }
)
infinite.push(`${r.status} ${r.data.length}`)
return null
}
function Plain() {
const r = useLiveQuery({
query: (q) => q.from({ e: events }).orderBy(({ e }) => e.n).limit(10),
})
plain.push(`${r.status} ${r.data.length}`)
return null
}
await act(async () => { render(<Infinite />) })
await act(async () => { render(<Plain />) })
console.log(infinite, plain)
Observed (status and data length per render)
useLiveInfiniteQuery [ 'idle 0', 'ready 10' ]
useLiveQuery [ 'ready 10' ]
Expected
useLiveInfiniteQuery [ 'ready 10' ]
Proposed fix
I'd rather not just flip it to startSync: true. My reading of #1675 is that it went to false so a render that never commits doesn't leave a started sync behind. useLiveQuery already handles that case: it starts sync during render with gcTime: 1, and a collection nobody subscribes to is cleaned up after that. The infinite hook already passes the same gcTime (DEFAULT_GC_TIME_MS), so it could start sync in render the same way and let gc reclaim abandoned ones. I tried flipping startSync to true in the built dist/esm/useLiveInfiniteQuery.js and the repro above logs [ 'ready 10' ]. I haven't run it under StrictMode or concurrent abandoned renders, so that part needs checking against the existing hook tests.
Happy to open a PR if that direction is fine.
Versions
- @tanstack/react-db 0.5.3
- @tanstack/db 0.11.3
- react / react-dom 19.3.0
- vitest 5.0.3, jsdom, @testing-library/react 16.3.3
- Lingua principale
- TypeScript
- Stelle
- 3.9k
- Fork
- 268
- Merge medio
- 1g 3h
- PR unite (30g)
- 193
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/db
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
Debounce and throttle paced mutations allow concurrent persistence despite the documented single-flight contractForse già presa @KyleAMathews l’ha presa oggi. Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 68/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
TanStack/db#1972 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 45/100
I maintainer di solito rispondono entro 1 giorno
Issue simili
-
enhancement
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
I maintainer di solito rispondono entro 1 giorno
-
[Bug] remember() with special characters in namespace hangs until timeout instead of returning 400Apertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
MystenLabs/MemWal#1133 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
bug user-priority/P2
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 92/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 Meno di un'ora Idoneità per principianti 88/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
Effect-TS/effect#8881 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno