Skip to content

$ref โ€‹

The $ref composable provides a lightweight way to access a Firestore document reactively through the browser's IndexedDB cache, automatically pulling from cache on mount.

๐Ÿ”ง Purpose โ€‹

This utility allows your components to bind to a Firestore document reactively without making live queries every time. Instead, data is served from local IndexedDB and kept up to date automatically by syncing with Firestore in the background. Handles deduplication so you can call the same doc in many queries and only ever have one listener at a time.

๐Ÿงช API โ€‹

Ref may only be used in a component lifecycle to avoid memory leaks.

ts
$ref(docPath: string): ComputedRef<any>

Parameters โ€‹

  • docPath (string): The full path of the Firestore document you want to observe. Example: users/abc123.

Returns โ€‹

  • A computed ref that tracks the live value of the document from IndexedDB.

๐Ÿ’ก Usage โ€‹

ts
const user = $ref("users/abc123")

watchEffect(() => {
    console.log("User data:", user.value)
})
  • โœ… Automatically pulls from cache
  • ๐Ÿ” Listens for updates via $pool.listenToDocument
  • ๐Ÿงน Cleans up listeners on unmount

๐Ÿง  How It Works โ€‹

  1. Checks if the client is running (import.meta.client). If not, returns a null ref.

  2. If a listener already exists for that document, reuses the existing one.

  3. Otherwise:

    • Initializes an IndexedDB entry using useIDBKeyval from @vueuse
    • Registers a Firestore listener via $pool.listenToDocument
    • Sets up a Vue computed ref to track the IDB value
    • Automatically unsubscribes from the Firestore listener when the component is unmounted

๐Ÿ›‘ Server-Side Safety โ€‹

If the utility is called in a server context (e.g., during SSR), it returns a computed(() => null) to avoid breaking hydration.

๐Ÿ“ฆ Dependencies โ€‹

๐Ÿงผ Best Practices โ€‹

  • Use $ref when you want a single document to be tracked and reactive in your component
  • Combine with $query to build composite UIs from cached reactive collections
  • Don't rely on $ref for one-off reads โ€” use $doc.get() instead for direct results

๐Ÿ› ๏ธ Example Use Case โ€‹

ts
<script setup>
const currentInvoice = $ref("invoices/abc123")
</script>

<template>
  <div v-if="currentInvoice">
    <h2>{{ currentInvoice.title }}</h2>
    <p>{{ currentInvoice.amount }} USD</p>
  </div>
</template>

๐Ÿค– Internal Notes โ€‹

  • Relies on $pool for subscription management
  • listeners is a map shared across documents to avoid duplicate listeners
  • All document data is stored under the key arkfire:<docPath> in IndexedDB
  • [$query] - for querying multiple documents as a collection
  • [$doc] - for CRUD operations
  • [$pool] - manages live listeners and cache sync