@@ -187,9 +187,11 @@ export function useLiveQuery(
187
187
typeof configOrQueryOrCollection . id === `string`
188
188
189
189
// Use refs to cache collection and track dependencies
190
- const collectionRef = useRef < any > ( null )
190
+ const collectionRef = useRef < Collection < object , string | number , { } > | null > (
191
+ null
192
+ )
191
193
const depsRef = useRef < Array < unknown > | null > ( null )
192
- const configRef = useRef < any > ( null )
194
+ const configRef = useRef < unknown > ( null )
193
195
194
196
// Check if we need to create/recreate the collection
195
197
const needsNewCollection =
@@ -214,13 +216,13 @@ export function useLiveQuery(
214
216
query : configOrQueryOrCollection ,
215
217
startSync : true ,
216
218
gcTime : 0 , // Live queries created by useLiveQuery are cleaned up immediately
217
- } )
219
+ } ) as unknown as Collection < object , string | number , { } >
218
220
} else {
219
221
collectionRef . current = createLiveQueryCollection ( {
220
222
startSync : true ,
221
223
gcTime : 0 , // Live queries created by useLiveQuery are cleaned up immediately
222
224
...configOrQueryOrCollection ,
223
- } )
225
+ } ) as unknown as Collection < object , string | number , { } >
224
226
}
225
227
depsRef . current = [ ...deps ]
226
228
}
@@ -229,10 +231,8 @@ export function useLiveQuery(
229
231
// Use refs to track version and memoized snapshot
230
232
const versionRef = useRef ( 0 )
231
233
const snapshotRef = useRef < {
232
- state : Map < any , any >
233
- data : Array < any >
234
- collection : Collection < any , any , any >
235
- _version : number
234
+ collection : Collection < object , string | number , { } >
235
+ version : number
236
236
} | null > ( null )
237
237
238
238
// Reset refs when collection changes
@@ -248,6 +248,7 @@ export function useLiveQuery(
248
248
if ( ! subscribeRef . current || needsNewCollection ) {
249
249
subscribeRef . current = ( onStoreChange : ( ) => void ) => {
250
250
const unsubscribe = collectionRef . current ! . subscribeChanges ( ( ) => {
251
+ // Bump version on any change; getSnapshot will rebuild next time
251
252
versionRef . current += 1
252
253
onStoreChange ( )
253
254
} )
@@ -260,9 +261,8 @@ export function useLiveQuery(
260
261
// Create stable getSnapshot function using ref
261
262
const getSnapshotRef = useRef <
262
263
| ( ( ) => {
263
- state : Map < any , any >
264
- data : Array < any >
265
- collection : Collection < any , any , any >
264
+ collection : Collection < object , string | number , { } >
265
+ version : number
266
266
} )
267
267
| null
268
268
> ( null )
@@ -271,20 +271,15 @@ export function useLiveQuery(
271
271
const currentVersion = versionRef . current
272
272
const currentCollection = collectionRef . current !
273
273
274
- // If we don't have a snapshot or the version changed, create a new one
274
+ // Recreate snapshot object only if version/collection changed
275
275
if (
276
276
! snapshotRef . current ||
277
- snapshotRef . current . _version !== currentVersion
277
+ snapshotRef . current . version !== currentVersion ||
278
+ snapshotRef . current . collection !== currentCollection
278
279
) {
279
280
snapshotRef . current = {
280
- get state ( ) {
281
- return new Map ( currentCollection . entries ( ) )
282
- } ,
283
- get data ( ) {
284
- return Array . from ( currentCollection . values ( ) )
285
- } ,
286
281
collection : currentCollection ,
287
- _version : currentVersion ,
282
+ version : currentVersion ,
288
283
}
289
284
}
290
285
@@ -298,17 +293,52 @@ export function useLiveQuery(
298
293
getSnapshotRef . current
299
294
)
300
295
301
- return {
302
- state : snapshot . state ,
303
- data : snapshot . data ,
304
- collection : snapshot . collection ,
305
- status : snapshot . collection . status ,
306
- isLoading :
307
- snapshot . collection . status === `loading` ||
308
- snapshot . collection . status === `initialCommit` ,
309
- isReady : snapshot . collection . status === `ready` ,
310
- isIdle : snapshot . collection . status === `idle` ,
311
- isError : snapshot . collection . status === `error` ,
312
- isCleanedUp : snapshot . collection . status === `cleaned-up` ,
296
+ // Track last snapshot (from useSyncExternalStore) and the returned value separately
297
+ const returnedSnapshotRef = useRef < {
298
+ collection : Collection < object , string | number , { } >
299
+ version : number
300
+ } | null > ( null )
301
+ // Keep implementation return loose to satisfy overload signatures
302
+ const returnedRef = useRef < any > ( null )
303
+
304
+ // Rebuild returned object only when the snapshot changes (version or collection identity)
305
+ if (
306
+ ! returnedSnapshotRef . current ||
307
+ returnedSnapshotRef . current . version !== snapshot . version ||
308
+ returnedSnapshotRef . current . collection !== snapshot . collection
309
+ ) {
310
+ // Capture a stable view of entries for this snapshot to avoid tearing
311
+ const entries = Array . from ( snapshot . collection . entries ( ) )
312
+ let stateCache : Map < string | number , unknown > | null = null
313
+ let dataCache : Array < unknown > | null = null
314
+
315
+ returnedRef . current = {
316
+ get state ( ) {
317
+ if ( ! stateCache ) {
318
+ stateCache = new Map ( entries )
319
+ }
320
+ return stateCache
321
+ } ,
322
+ get data ( ) {
323
+ if ( ! dataCache ) {
324
+ dataCache = entries . map ( ( [ , value ] ) => value )
325
+ }
326
+ return dataCache
327
+ } ,
328
+ collection : snapshot . collection ,
329
+ status : snapshot . collection . status ,
330
+ isLoading :
331
+ snapshot . collection . status === `loading` ||
332
+ snapshot . collection . status === `initialCommit` ,
333
+ isReady : snapshot . collection . status === `ready` ,
334
+ isIdle : snapshot . collection . status === `idle` ,
335
+ isError : snapshot . collection . status === `error` ,
336
+ isCleanedUp : snapshot . collection . status === `cleaned-up` ,
337
+ }
338
+
339
+ // Remember the snapshot that produced this returned value
340
+ returnedSnapshotRef . current = snapshot
313
341
}
342
+
343
+ return returnedRef . current !
314
344
}
0 commit comments