in packages/firestore/src/api/reference_impl.ts [589:699]
export function onSnapshot<T>(
query: Query<T>,
onNext: (snapshot: QuerySnapshot<T>) => void,
onError?: (error: FirestoreError) => void,
onCompletion?: () => void
): Unsubscribe;
/**
* Attaches a listener for `QuerySnapshot` events. You may either pass
* individual `onNext` and `onError` callbacks or pass a single observer
* object with `next` and `error` callbacks. The listener can be cancelled by
* calling the function that is returned when `onSnapshot` is called.
*
* NOTE: Although an `onCompletion` callback can be provided, it will
* never be called because the snapshot stream is never-ending.
*
* @param query - The query to listen to.
* @param options - Options controlling the listen behavior.
* @param onNext - A callback to be called every time a new `QuerySnapshot`
* is available.
* @param onCompletion - Can be provided, but will not be called since streams are
* never ending.
* @param onError - A callback to be called if the listen fails or is
* cancelled. No further callbacks will occur.
* @returns An unsubscribe function that can be called to cancel
* the snapshot listener.
*/
export function onSnapshot<T>(
query: Query<T>,
options: SnapshotListenOptions,
onNext: (snapshot: QuerySnapshot<T>) => void,
onError?: (error: FirestoreError) => void,
onCompletion?: () => void
): Unsubscribe;
export function onSnapshot<T>(
reference: Query<T> | DocumentReference<T>,
...args: unknown[]
): Unsubscribe {
reference = getModularInstance(reference);
let options: SnapshotListenOptions = {
includeMetadataChanges: false
};
let currArg = 0;
if (typeof args[currArg] === 'object' && !isPartialObserver(args[currArg])) {
options = args[currArg] as SnapshotListenOptions;
currArg++;
}
const internalOptions = {
includeMetadataChanges: options.includeMetadataChanges
};
if (isPartialObserver(args[currArg])) {
const userObserver = args[currArg] as PartialObserver<QuerySnapshot<T>>;
args[currArg] = userObserver.next?.bind(userObserver);
args[currArg + 1] = userObserver.error?.bind(userObserver);
args[currArg + 2] = userObserver.complete?.bind(userObserver);
}
let observer: PartialObserver<ViewSnapshot>;
let firestore: Firestore;
let internalQuery: InternalQuery;
if (reference instanceof DocumentReference) {
firestore = cast(reference.firestore, Firestore);
internalQuery = newQueryForPath(reference._key.path);
observer = {
next: snapshot => {
if (args[currArg]) {
(args[currArg] as NextFn<DocumentSnapshot<T>>)(
convertToDocSnapshot(
firestore,
reference as DocumentReference<T>,
snapshot
)
);
}
},
error: args[currArg + 1] as ErrorFn,
complete: args[currArg + 2] as CompleteFn
};
} else {
const query = cast<Query<T>>(reference, Query);
firestore = cast(query.firestore, Firestore);
internalQuery = query._query;
const userDataWriter = new ExpUserDataWriter(firestore);
observer = {
next: snapshot => {
if (args[currArg]) {
(args[currArg] as NextFn<QuerySnapshot<T>>)(
new QuerySnapshot(firestore, userDataWriter, query, snapshot)
);
}
},
error: args[currArg + 1] as ErrorFn,
complete: args[currArg + 2] as CompleteFn
};
validateHasExplicitOrderByForLimitToLast(reference._query);
}
const client = ensureFirestoreConfigured(firestore);
return firestoreClientListen(
client,
internalQuery,
internalOptions,
observer
);
}