Skip to content

Observable Document

ObservableDocument wraps a single Firestore document with MobX observability. It automatically manages snapshot listeners and exposes reactive properties.

Constructor

ts
new ObservableDocument<T>(source?: DocumentReference | CollectionReference, options?: Options)

The source parameter accepts either a DocumentReference (for a specific document) or a CollectionReference (when the document ID is not yet known). If a CollectionReference is passed, use attachTo() to set the document ID later.

Options

OptionTypeDefaultDescription
debugbooleanfalseEnable debug logging to the console.
lazybooleanfalseDefer loading until the document is observed. See Lazy Loading.

Properties

PropertyTypeDescription
dataT | undefinedThe document data, or undefined if not loaded or not found.
documentDocument<T>Object with id, data, and ref. Throws if not available.
idstringThe document ID, or "__no_id" if no reference is set.
isLoadingbooleanWhether the document is currently loading.
pathstring | undefinedThe full Firestore path of the document.

Methods

ready()

Returns a Promise<T | undefined> that resolves when the document data is first available. If no snapshot listener is active, it performs a one-time fetch.

ts
const data = await author.ready();

attachTo(documentId?: string)

Switch the document to a different ID within the same collection. Pass undefined to detach and clear the data. Returns this for chaining.

This is useful when the document ID depends on runtime state, such as user interaction or data from another document:

ts
class AuthorStore {
  private _author = createObservableDocument(refs.authors);

  loadAuthor(authorId: string) {
    this._author.attachTo(authorId);
  }

  clearAuthor() {
    this._author.attachTo(undefined);
  }

  get author() {
    return this._author.data;
  }
}

You can chain attachTo with ready() when you need to wait for the data:

ts
const data = await this._author.attachTo(authorId).ready();

onError(callback)

Register an error handler. Without this, errors are thrown. Returns this for chaining.

ts
author.onError((err) => Sentry.captureException(err));

onData(callback)

Register a callback that fires whenever new data arrives from Firestore. Returns this for chaining.

This is the primary mechanism for cascading data loads, where one document's data determines what other documents to load:

ts
this._book = createObservableDocument(refs.books);
this._author = createObservableDocument(refs.authors);

this._book.attachTo(bookId);

this._book.onData((data) => {
  // When the book loads, attach to its author
  this._author.attachTo(data.author_id);
});

TIP

The onData callback fires before the loading state is updated. This ensures dependent observables can begin loading before any component sees isLoading: false on the parent, preventing flicker in combined loading states like this._book.isLoading || this._author.isLoading.

Factory Function

ts
import { createObservableDocument } from "firestore-mobx";

const doc = createObservableDocument(typedDocumentRef);

createObservableDocument infers the type T from the reference, which is useful when working with typed-firestore references where types flow from the ref definitions.

Released under the MIT License.