Skip to content

[Vue] useLiveQuery isLoading state does not update correctly on initial loadΒ #370

@asforrester

Description

@asforrester

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

  1. Open code sandbox
  2. Wait for the preview to load and data to fetch
  3. "Actual Behaviour" column on the left. isLoading remains true despite data being loaded
  4. 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:

  1. Collection created, sync starts
  2. Reaches 'initialCommit' synchronously
  3. Vue captures: status.value = currentCollection.status // 'initialCommit'
  4. subscribeChanges registered
  5. [10ms delay]
  6. Async completes, collection internally transitions to 'ready'
  7. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions