-
Notifications
You must be signed in to change notification settings - Fork 77
Description
The bug
useLiveQuery
with Vue gets stuck in loading state after data successfully loads when there's an async delay in the sync process. The isLoading
computed property remains true and status remains 'initialCommit' even though the underlying collection has transitioned to 'ready' status.
This only seems to occur with asynchronous data loading. Synchronous data loading works as expected.
Expected behaviour
- When collection status becomes 'ready',
isLoading
should be false status
should reflect the collection's actual status ('ready')isReady
should be true
Actual behavior
isLoading
remains true indefinitely (or until another update triggers reactivity)status
stays as 'initialCommit'isReady
remains false
Minimal, reproducible example
https://codesandbox.io/p/devbox/tanstack-vue-db-hy288m
The sandbox demonstrates both behaviors side-by-side:
- Left column: Shows the bug (status stuck)
- Right column: Shows expected final state
You'll see I made a small change to useLiveQuery that seems to resolve the issue, but honestly I'm not at all sure if this is the correct fix in the full context:
// Initialize data array in correct order
syncDataFromCollection(currentCollection)
currentCollection.onFirstReady(() => {
nextTick(() => {
status.value = currentCollection.status
})
})
// Subscribe to collection changes with granular updates
currentUnsubscribe = currentCollection.subscribeChanges(
Steps to reproduce
- Open code sandbox
- Wait for the preview to load and data to fetch
- "Actual Behaviour" column on the left.
isLoading
remains true despite data being loaded - Compare with the right column showing expected behaviour
Additional Context
TanStack DB version: 0.0.33
Vue version: 3.5.18
If it's helpful, here's Claude's take on the root cause (claims 9.5/10 confidence...always does)
When there's an async delay (even 10ms), the collection reaches 'initialCommit' synchronously, then Vue captures this status with status.value = currentCollection.status. Later, when the async operation completes and the collection transitions to 'ready', this is a status-only change with no data changes. Since subscribeChanges only fires its callback when data changes (not on status changes), Vue's reactive status.value never updates from 'initialCommit' to 'ready'.
The sequence:
- Collection created, sync starts
- Reaches 'initialCommit' synchronously
- Vue captures: status.value = currentCollection.status // 'initialCommit'
- subscribeChanges registered
- [10ms delay]
- Async completes, collection internally transitions to 'ready'
- No data changed = no callback = Vue still shows 'initialCommit'
Without the delay, the collection reaches 'ready' synchronously before Vue captures the status, so it works. With the delay, Vue captures an intermediate state and has no way to know when it changes.
P.S. Thanks the most for all your work on this library, I'm pretty excited about it.