or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-types.mddatabase-operations.mdindex.mdmodular-api.mdoffline-network.mdquerying-filtering.mdrealtime-sync.mdtransactions-batches.md

realtime-sync.mddocs/

0

# Real-time Data Synchronization

1

2

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

3

4

## Capabilities

5

6

### Document Listeners

7

8

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

9

10

```typescript { .api }

11

/**

12

* Listen to document changes with observer pattern

13

* @param observer - Observer object with next, error, and complete handlers

14

* @returns Unsubscribe function to stop listening

15

*/

16

onSnapshot(observer: {

17

next?: (snapshot: FirebaseFirestoreTypes.DocumentSnapshot<T>) => void;

18

error?: (error: Error) => void;

19

complete?: () => void;

20

}): () => void;

21

22

/**

23

* Listen to document changes with observer pattern and options

24

* @param options - Snapshot listen options

25

* @param observer - Observer object with handlers

26

* @returns Unsubscribe function to stop listening

27

*/

28

onSnapshot(

29

options: FirebaseFirestoreTypes.SnapshotListenOptions,

30

observer: {

31

next?: (snapshot: FirebaseFirestoreTypes.DocumentSnapshot<T>) => void;

32

error?: (error: Error) => void;

33

complete?: () => void;

34

}

35

): () => void;

36

37

/**

38

* Listen to document changes with callback functions

39

* @param onNext - Function called on each snapshot

40

* @param onError - Optional error handler

41

* @param onCompletion - Optional completion handler

42

* @returns Unsubscribe function to stop listening

43

*/

44

onSnapshot(

45

onNext: (snapshot: FirebaseFirestoreTypes.DocumentSnapshot<T>) => void,

46

onError?: (error: Error) => void,

47

onCompletion?: () => void

48

): () => void;

49

50

/**

51

* Listen to document changes with options and callback functions

52

* @param options - Snapshot listen options

53

* @param onNext - Function called on each snapshot

54

* @param onError - Optional error handler

55

* @param onCompletion - Optional completion handler

56

* @returns Unsubscribe function to stop listening

57

*/

58

onSnapshot(

59

options: FirebaseFirestoreTypes.SnapshotListenOptions,

60

onNext: (snapshot: FirebaseFirestoreTypes.DocumentSnapshot<T>) => void,

61

onError?: (error: Error) => void,

62

onCompletion?: () => void

63

): () => void;

64

```

65

66

**Usage Examples:**

67

68

```typescript

69

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

70

71

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

72

73

// Basic listener with callback

74

const unsubscribe = userDoc.onSnapshot(snapshot => {

75

if (snapshot.exists) {

76

console.log('User data:', snapshot.data());

77

} else {

78

console.log('User does not exist');

79

}

80

});

81

82

// Listener with error handling

83

const unsubscribeWithError = userDoc.onSnapshot(

84

snapshot => {

85

console.log('User updated:', snapshot.data());

86

},

87

error => {

88

console.error('Error listening to user:', error);

89

}

90

);

91

92

// Observer pattern

93

const unsubscribeObserver = userDoc.onSnapshot({

94

next: snapshot => {

95

console.log('User data:', snapshot.data());

96

},

97

error: error => {

98

console.error('Listener error:', error);

99

},

100

complete: () => {

101

console.log('Listener completed');

102

}

103

});

104

105

// Include metadata changes

106

const unsubscribeWithMetadata = userDoc.onSnapshot(

107

{ includeMetadataChanges: true },

108

snapshot => {

109

console.log('Data:', snapshot.data());

110

console.log('From cache:', snapshot.metadata.fromCache);

111

console.log('Has pending writes:', snapshot.metadata.hasPendingWrites);

112

}

113

);

114

115

// Stop listening

116

unsubscribe();

117

```

118

119

### Query Listeners

120

121

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

122

123

```typescript { .api }

124

/**

125

* Listen to query changes with observer pattern

126

* @param observer - Observer object with next, error, and complete handlers

127

* @returns Unsubscribe function to stop listening

128

*/

129

onSnapshot(observer: {

130

next?: (snapshot: FirebaseFirestoreTypes.QuerySnapshot<T>) => void;

131

error?: (error: Error) => void;

132

complete?: () => void;

133

}): () => void;

134

135

/**

136

* Listen to query changes with observer pattern and options

137

* @param options - Snapshot listen options

138

* @param observer - Observer object with handlers

139

* @returns Unsubscribe function to stop listening

140

*/

141

onSnapshot(

142

options: FirebaseFirestoreTypes.SnapshotListenOptions,

143

observer: {

144

next?: (snapshot: FirebaseFirestoreTypes.QuerySnapshot<T>) => void;

145

error?: (error: Error) => void;

146

complete?: () => void;

147

}

148

): () => void;

149

150

/**

151

* Listen to query changes with callback functions

152

* @param onNext - Function called on each snapshot

153

* @param onError - Optional error handler

154

* @param onCompletion - Optional completion handler

155

* @returns Unsubscribe function to stop listening

156

*/

157

onSnapshot(

158

onNext: (snapshot: FirebaseFirestoreTypes.QuerySnapshot<T>) => void,

159

onError?: (error: Error) => void,

160

onCompletion?: () => void

161

): () => void;

162

163

/**

164

* Listen to query changes with options and callback functions

165

* @param options - Snapshot listen options

166

* @param onNext - Function called on each snapshot

167

* @param onError - Optional error handler

168

* @param onCompletion - Optional completion handler

169

* @returns Unsubscribe function to stop listening

170

*/

171

onSnapshot(

172

options: FirebaseFirestoreTypes.SnapshotListenOptions,

173

onNext: (snapshot: FirebaseFirestoreTypes.QuerySnapshot<T>) => void,

174

onError?: (error: Error) => void,

175

onCompletion?: () => void

176

): () => void;

177

```

178

179

**Usage Examples:**

180

181

```typescript

182

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

183

184

const usersQuery = firestore()

185

.collection('users')

186

.where('active', '==', true)

187

.orderBy('createdAt', 'desc');

188

189

// Basic query listener

190

const unsubscribe = usersQuery.onSnapshot(snapshot => {

191

console.log(`Found ${snapshot.size} active users`);

192

193

snapshot.forEach(doc => {

194

console.log(doc.id, '=>', doc.data());

195

});

196

});

197

198

// Listen to document changes

199

const unsubscribeWithChanges = usersQuery.onSnapshot(snapshot => {

200

snapshot.docChanges().forEach(change => {

201

const doc = change.doc;

202

203

switch (change.type) {

204

case 'added':

205

console.log('New user:', doc.data());

206

break;

207

case 'modified':

208

console.log('Updated user:', doc.data());

209

break;

210

case 'removed':

211

console.log('Removed user:', doc.data());

212

break;

213

}

214

});

215

});

216

217

// Include metadata changes to detect local vs server updates

218

const unsubscribeMetadata = usersQuery.onSnapshot(

219

{ includeMetadataChanges: true },

220

snapshot => {

221

if (snapshot.metadata.fromCache) {

222

console.log('Data from cache');

223

} else {

224

console.log('Data from server');

225

}

226

227

snapshot.docChanges({ includeMetadataChanges: true }).forEach(change => {

228

if (change.doc.metadata.hasPendingWrites) {

229

console.log('Document has local changes');

230

}

231

});

232

}

233

);

234

235

// Observer pattern with error handling

236

const unsubscribeObserver = usersQuery.onSnapshot({

237

next: snapshot => {

238

console.log('Query updated:', snapshot.size, 'documents');

239

},

240

error: error => {

241

console.error('Query listener error:', error);

242

}

243

});

244

245

// Stop listening

246

unsubscribe();

247

```

248

249

### Snapshots in Sync

250

251

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

252

253

```typescript { .api }

254

/**

255

* Listen for snapshots in sync events with observer pattern

256

* @param observer - Observer object with handlers

257

* @returns Unsubscribe function to stop listening

258

*/

259

onSnapshotsInSync(observer: {

260

next?: () => void;

261

error?: (error: Error) => void;

262

complete?: () => void;

263

}): () => void;

264

265

/**

266

* Listen for snapshots in sync events with callback

267

* @param onSync - Function called when snapshots are in sync

268

* @returns Unsubscribe function to stop listening

269

*/

270

onSnapshotsInSync(onSync: () => void): () => void;

271

```

272

273

**Usage Examples:**

274

275

```typescript

276

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

277

278

// Basic sync listener

279

const unsubscribeSync = firestore().onSnapshotsInSync(() => {

280

console.log('All snapshots are now in sync with the server');

281

});

282

283

// Observer pattern

284

const unsubscribeSyncObserver = firestore().onSnapshotsInSync({

285

next: () => {

286

console.log('Snapshots in sync');

287

},

288

error: error => {

289

console.error('Sync error:', error);

290

}

291

});

292

293

// Stop listening

294

unsubscribeSync();

295

```

296

297

### Managing Multiple Listeners

298

299

Best practices for handling multiple real-time listeners efficiently.

300

301

**Usage Examples:**

302

303

```typescript

304

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

305

306

class UserProfileComponent {

307

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

308

309

componentDidMount() {

310

const userId = 'currentUserId';

311

312

// Listen to user profile

313

const userUnsubscribe = firestore()

314

.collection('users')

315

.doc(userId)

316

.onSnapshot(snapshot => {

317

this.setState({ user: snapshot.data() });

318

});

319

320

// Listen to user's posts

321

const postsUnsubscribe = firestore()

322

.collection('posts')

323

.where('authorId', '==', userId)

324

.orderBy('createdAt', 'desc')

325

.onSnapshot(snapshot => {

326

const posts = snapshot.docs.map(doc => ({

327

id: doc.id,

328

...doc.data()

329

}));

330

this.setState({ posts });

331

});

332

333

// Listen to notifications

334

const notificationsUnsubscribe = firestore()

335

.collection('notifications')

336

.where('userId', '==', userId)

337

.where('read', '==', false)

338

.onSnapshot(snapshot => {

339

this.setState({ unreadNotifications: snapshot.size });

340

});

341

342

// Store all unsubscribers

343

this.unsubscribers = [

344

userUnsubscribe,

345

postsUnsubscribe,

346

notificationsUnsubscribe

347

];

348

}

349

350

componentWillUnmount() {

351

// Clean up all listeners

352

this.unsubscribers.forEach(unsubscribe => unsubscribe());

353

this.unsubscribers = [];

354

}

355

}

356

```

357

358

## Types

359

360

```typescript { .api }

361

interface SnapshotListenOptions {

362

/**

363

* Whether to include metadata-only changes

364

* Includes changes to document metadata like pending writes or cache status

365

*/

366

includeMetadataChanges: boolean;

367

}

368

369

interface SnapshotMetadata {

370

/**

371

* True if the snapshot contains the result of local writes not yet committed to the backend

372

*/

373

readonly fromCache: boolean;

374

375

/**

376

* True if the snapshot includes local writes that have not yet been committed to the backend

377

*/

378

readonly hasPendingWrites: boolean;

379

380

/**

381

* Check if two metadata objects are equal

382

*/

383

isEqual(other: FirebaseFirestoreTypes.SnapshotMetadata): boolean;

384

}

385

386

interface DocumentChange<T = FirebaseFirestoreTypes.DocumentData> {

387

/**

388

* The document affected by this change

389

*/

390

readonly doc: FirebaseFirestoreTypes.QueryDocumentSnapshot<T>;

391

392

/**

393

* The new index of the changed document in the result set (-1 if removed)

394

*/

395

readonly newIndex: number;

396

397

/**

398

* The old index of the changed document in the result set (-1 if added)

399

*/

400

readonly oldIndex: number;

401

402

/**

403

* The type of change ('added', 'modified', or 'removed')

404

*/

405

readonly type: FirebaseFirestoreTypes.DocumentChangeType;

406

}

407

408

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

409

410

/**

411

* Unsubscribe function returned by snapshot listeners

412

*/

413

type Unsubscribe = () => void;

414

```

415

416

## Error Handling

417

418

```typescript { .api }

419

interface FirestoreError extends Error {

420

/**

421

* Error code indicating the type of error

422

*/

423

readonly code: FirebaseFirestoreTypes.FirestoreErrorCode;

424

425

/**

426

* Human-readable error message

427

*/

428

readonly message: string;

429

}

430

431

type FirestoreErrorCode =

432

| 'cancelled'

433

| 'unknown'

434

| 'invalid-argument'

435

| 'deadline-exceeded'

436

| 'not-found'

437

| 'already-exists'

438

| 'permission-denied'

439

| 'resource-exhausted'

440

| 'failed-precondition'

441

| 'aborted'

442

| 'out-of-range'

443

| 'unimplemented'

444

| 'internal'

445

| 'unavailable'

446

| 'data-loss'

447

| 'unauthenticated';

448

```

449

450

**Error Handling Examples:**

451

452

```typescript

453

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

454

455

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

456

457

const unsubscribe = userDoc.onSnapshot(

458

snapshot => {

459

// Handle successful snapshot

460

console.log('User data:', snapshot.data());

461

},

462

error => {

463

// Handle errors

464

switch (error.code) {

465

case 'permission-denied':

466

console.error('User does not have permission to access this document');

467

break;

468

case 'unavailable':

469

console.error('Service is currently unavailable');

470

break;

471

case 'unauthenticated':

472

console.error('User is not authenticated');

473

break;

474

default:

475

console.error('Unknown error:', error.message);

476

}

477

}

478

);

479

```