CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-native-firebase--firestore

React Native Firebase Cloud Firestore provides a NoSQL document database with real-time synchronization capabilities.

Pending
Overview
Eval results
Files

realtime-sync.mddocs/

Real-time Data Synchronization

Real-time listeners for documents and collections with configurable options for metadata changes and error handling.

Capabilities

Document Listeners

Listen to real-time changes on individual documents with multiple callback patterns.

/**
 * Listen to document changes with observer pattern
 * @param observer - Observer object with next, error, and complete handlers
 * @returns Unsubscribe function to stop listening
 */
onSnapshot(observer: {
  next?: (snapshot: FirebaseFirestoreTypes.DocumentSnapshot<T>) => void;
  error?: (error: Error) => void;
  complete?: () => void;
}): () => void;

/**
 * Listen to document changes with observer pattern and options
 * @param options - Snapshot listen options
 * @param observer - Observer object with handlers
 * @returns Unsubscribe function to stop listening
 */
onSnapshot(
  options: FirebaseFirestoreTypes.SnapshotListenOptions,
  observer: {
    next?: (snapshot: FirebaseFirestoreTypes.DocumentSnapshot<T>) => void;
    error?: (error: Error) => void;
    complete?: () => void;
  }
): () => void;

/**
 * Listen to document changes with callback functions
 * @param onNext - Function called on each snapshot
 * @param onError - Optional error handler
 * @param onCompletion - Optional completion handler
 * @returns Unsubscribe function to stop listening
 */
onSnapshot(
  onNext: (snapshot: FirebaseFirestoreTypes.DocumentSnapshot<T>) => void,
  onError?: (error: Error) => void,
  onCompletion?: () => void
): () => void;

/**
 * Listen to document changes with options and callback functions
 * @param options - Snapshot listen options
 * @param onNext - Function called on each snapshot
 * @param onError - Optional error handler
 * @param onCompletion - Optional completion handler
 * @returns Unsubscribe function to stop listening
 */
onSnapshot(
  options: FirebaseFirestoreTypes.SnapshotListenOptions,
  onNext: (snapshot: FirebaseFirestoreTypes.DocumentSnapshot<T>) => void,
  onError?: (error: Error) => void,
  onCompletion?: () => void
): () => void;

Usage Examples:

import firestore from '@react-native-firebase/firestore';

const userDoc = firestore().collection('users').doc('userId');

// Basic listener with callback
const unsubscribe = userDoc.onSnapshot(snapshot => {
  if (snapshot.exists) {
    console.log('User data:', snapshot.data());
  } else {
    console.log('User does not exist');
  }
});

// Listener with error handling
const unsubscribeWithError = userDoc.onSnapshot(
  snapshot => {
    console.log('User updated:', snapshot.data());
  },
  error => {
    console.error('Error listening to user:', error);
  }
);

// Observer pattern
const unsubscribeObserver = userDoc.onSnapshot({
  next: snapshot => {
    console.log('User data:', snapshot.data());
  },
  error: error => {
    console.error('Listener error:', error);
  },
  complete: () => {
    console.log('Listener completed');
  }
});

// Include metadata changes
const unsubscribeWithMetadata = userDoc.onSnapshot(
  { includeMetadataChanges: true },
  snapshot => {
    console.log('Data:', snapshot.data());
    console.log('From cache:', snapshot.metadata.fromCache);
    console.log('Has pending writes:', snapshot.metadata.hasPendingWrites);
  }
);

// Stop listening
unsubscribe();

Query Listeners

Listen to real-time changes on query results, receiving updates when documents are added, removed, or modified.

/**
 * Listen to query changes with observer pattern
 * @param observer - Observer object with next, error, and complete handlers
 * @returns Unsubscribe function to stop listening
 */
onSnapshot(observer: {
  next?: (snapshot: FirebaseFirestoreTypes.QuerySnapshot<T>) => void;
  error?: (error: Error) => void;
  complete?: () => void;
}): () => void;

/**
 * Listen to query changes with observer pattern and options
 * @param options - Snapshot listen options
 * @param observer - Observer object with handlers
 * @returns Unsubscribe function to stop listening
 */
onSnapshot(
  options: FirebaseFirestoreTypes.SnapshotListenOptions,
  observer: {
    next?: (snapshot: FirebaseFirestoreTypes.QuerySnapshot<T>) => void;
    error?: (error: Error) => void;
    complete?: () => void;
  }
): () => void;

/**
 * Listen to query changes with callback functions
 * @param onNext - Function called on each snapshot
 * @param onError - Optional error handler
 * @param onCompletion - Optional completion handler
 * @returns Unsubscribe function to stop listening
 */
onSnapshot(
  onNext: (snapshot: FirebaseFirestoreTypes.QuerySnapshot<T>) => void,
  onError?: (error: Error) => void,
  onCompletion?: () => void
): () => void;

/**
 * Listen to query changes with options and callback functions
 * @param options - Snapshot listen options
 * @param onNext - Function called on each snapshot
 * @param onError - Optional error handler
 * @param onCompletion - Optional completion handler
 * @returns Unsubscribe function to stop listening
 */
onSnapshot(
  options: FirebaseFirestoreTypes.SnapshotListenOptions,
  onNext: (snapshot: FirebaseFirestoreTypes.QuerySnapshot<T>) => void,
  onError?: (error: Error) => void,
  onCompletion?: () => void
): () => void;

Usage Examples:

import firestore from '@react-native-firebase/firestore';

const usersQuery = firestore()
  .collection('users')
  .where('active', '==', true)
  .orderBy('createdAt', 'desc');

// Basic query listener
const unsubscribe = usersQuery.onSnapshot(snapshot => {
  console.log(`Found ${snapshot.size} active users`);
  
  snapshot.forEach(doc => {
    console.log(doc.id, '=>', doc.data());
  });
});

// Listen to document changes
const unsubscribeWithChanges = usersQuery.onSnapshot(snapshot => {
  snapshot.docChanges().forEach(change => {
    const doc = change.doc;
    
    switch (change.type) {
      case 'added':
        console.log('New user:', doc.data());
        break;
      case 'modified':
        console.log('Updated user:', doc.data());
        break;
      case 'removed':
        console.log('Removed user:', doc.data());
        break;
    }
  });
});

// Include metadata changes to detect local vs server updates
const unsubscribeMetadata = usersQuery.onSnapshot(
  { includeMetadataChanges: true },
  snapshot => {
    if (snapshot.metadata.fromCache) {
      console.log('Data from cache');
    } else {
      console.log('Data from server');
    }
    
    snapshot.docChanges({ includeMetadataChanges: true }).forEach(change => {
      if (change.doc.metadata.hasPendingWrites) {
        console.log('Document has local changes');
      }
    });
  }
);

// Observer pattern with error handling
const unsubscribeObserver = usersQuery.onSnapshot({
  next: snapshot => {
    console.log('Query updated:', snapshot.size, 'documents');
  },
  error: error => {
    console.error('Query listener error:', error);
  }
});

// Stop listening
unsubscribe();

Snapshots in Sync

Listen for when all active listeners are in sync with the server.

/**
 * Listen for snapshots in sync events with observer pattern
 * @param observer - Observer object with handlers
 * @returns Unsubscribe function to stop listening
 */
onSnapshotsInSync(observer: {
  next?: () => void;
  error?: (error: Error) => void;
  complete?: () => void;
}): () => void;

/**
 * Listen for snapshots in sync events with callback
 * @param onSync - Function called when snapshots are in sync
 * @returns Unsubscribe function to stop listening
 */
onSnapshotsInSync(onSync: () => void): () => void;

Usage Examples:

import firestore from '@react-native-firebase/firestore';

// Basic sync listener
const unsubscribeSync = firestore().onSnapshotsInSync(() => {
  console.log('All snapshots are now in sync with the server');
});

// Observer pattern
const unsubscribeSyncObserver = firestore().onSnapshotsInSync({
  next: () => {
    console.log('Snapshots in sync');
  },
  error: error => {
    console.error('Sync error:', error);
  }
});

// Stop listening
unsubscribeSync();

Managing Multiple Listeners

Best practices for handling multiple real-time listeners efficiently.

Usage Examples:

import firestore from '@react-native-firebase/firestore';

class UserProfileComponent {
  private unsubscribers: Array<() => void> = [];

  componentDidMount() {
    const userId = 'currentUserId';
    
    // Listen to user profile
    const userUnsubscribe = firestore()
      .collection('users')
      .doc(userId)
      .onSnapshot(snapshot => {
        this.setState({ user: snapshot.data() });
      });

    // Listen to user's posts
    const postsUnsubscribe = firestore()
      .collection('posts')
      .where('authorId', '==', userId)
      .orderBy('createdAt', 'desc')
      .onSnapshot(snapshot => {
        const posts = snapshot.docs.map(doc => ({
          id: doc.id,
          ...doc.data()
        }));
        this.setState({ posts });
      });

    // Listen to notifications
    const notificationsUnsubscribe = firestore()
      .collection('notifications')
      .where('userId', '==', userId)
      .where('read', '==', false)
      .onSnapshot(snapshot => {
        this.setState({ unreadNotifications: snapshot.size });
      });

    // Store all unsubscribers
    this.unsubscribers = [
      userUnsubscribe,
      postsUnsubscribe,
      notificationsUnsubscribe
    ];
  }

  componentWillUnmount() {
    // Clean up all listeners
    this.unsubscribers.forEach(unsubscribe => unsubscribe());
    this.unsubscribers = [];
  }
}

Types

interface SnapshotListenOptions {
  /**
   * Whether to include metadata-only changes
   * Includes changes to document metadata like pending writes or cache status
   */
  includeMetadataChanges: boolean;
}

interface SnapshotMetadata {
  /**
   * True if the snapshot contains the result of local writes not yet committed to the backend
   */
  readonly fromCache: boolean;
  
  /**
   * True if the snapshot includes local writes that have not yet been committed to the backend
   */
  readonly hasPendingWrites: boolean;
  
  /**
   * Check if two metadata objects are equal
   */
  isEqual(other: FirebaseFirestoreTypes.SnapshotMetadata): boolean;
}

interface DocumentChange<T = FirebaseFirestoreTypes.DocumentData> {
  /**
   * The document affected by this change
   */
  readonly doc: FirebaseFirestoreTypes.QueryDocumentSnapshot<T>;
  
  /**
   * The new index of the changed document in the result set (-1 if removed)
   */
  readonly newIndex: number;
  
  /**
   * The old index of the changed document in the result set (-1 if added)
   */
  readonly oldIndex: number;
  
  /**
   * The type of change ('added', 'modified', or 'removed')
   */
  readonly type: FirebaseFirestoreTypes.DocumentChangeType;
}

type DocumentChangeType = 'added' | 'removed' | 'modified';

/**
 * Unsubscribe function returned by snapshot listeners
 */
type Unsubscribe = () => void;

Error Handling

interface FirestoreError extends Error {
  /**
   * Error code indicating the type of error
   */
  readonly code: FirebaseFirestoreTypes.FirestoreErrorCode;
  
  /**
   * Human-readable error message
   */
  readonly message: string;
}

type FirestoreErrorCode = 
  | 'cancelled'
  | 'unknown'
  | 'invalid-argument'
  | 'deadline-exceeded'
  | 'not-found'
  | 'already-exists'
  | 'permission-denied'
  | 'resource-exhausted'
  | 'failed-precondition'
  | 'aborted'
  | 'out-of-range'
  | 'unimplemented'
  | 'internal'
  | 'unavailable'
  | 'data-loss'
  | 'unauthenticated';

Error Handling Examples:

import firestore from '@react-native-firebase/firestore';

const userDoc = firestore().collection('users').doc('userId');

const unsubscribe = userDoc.onSnapshot(
  snapshot => {
    // Handle successful snapshot
    console.log('User data:', snapshot.data());
  },
  error => {
    // Handle errors
    switch (error.code) {
      case 'permission-denied':
        console.error('User does not have permission to access this document');
        break;
      case 'unavailable':
        console.error('Service is currently unavailable');
        break;
      case 'unauthenticated':
        console.error('User is not authenticated');
        break;
      default:
        console.error('Unknown error:', error.message);
    }
  }
);

Install with Tessl CLI

npx tessl i tessl/npm-react-native-firebase--firestore

docs

data-types.md

database-operations.md

index.md

modular-api.md

offline-network.md

querying-filtering.md

realtime-sync.md

transactions-batches.md

tile.json