Skip to content

Commit 788cc22

Browse files
committed
fix(database): react-native 0.73 compatibility
upstream EventEmitter made registrations fully private, and we were relying on them to implement specific-listener-removal to meet a firebase-js-sdk API contract implemented listener registration accounting in situ in place of previous style relying on upstream EventEmitter implementation
1 parent a899390 commit 788cc22

File tree

1 file changed

+43
-10
lines changed

1 file changed

+43
-10
lines changed

packages/database/lib/DatabaseSyncTree.js

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,32 @@ class DatabaseSyncTree {
2626
this._tree = {};
2727
this._reverseLookup = {};
2828

29+
// we need to be able to register multiple listeners for a single event,
30+
// *then delete a specific single listener for that event*, so we have to
31+
// be able to identify specific listeners for removal which means we need
32+
// to mirror the private registration accounting from upstream EventEmitter
33+
// so we have access here and can do our single emitter removal
34+
// This is a map of emitter-key <-> set of listener registrations
35+
// The listener registrations have { context, listener, remove() }
36+
this._registry = {};
37+
2938
SharedEventEmitter.addListener('database_sync_event', this._handleSyncEvent.bind(this));
3039
}
3140

3241
get native() {
3342
return NativeModules.RNFBDatabaseQueryModule;
3443
}
3544

45+
// from upstream EventEmitter: initialize registrations for an emitter key
46+
_allocate(registry, eventType) {
47+
let registrations = registry[eventType];
48+
if (registrations == null) {
49+
registrations = new Set();
50+
registry[eventType] = registrations;
51+
}
52+
return registrations;
53+
}
54+
3655
/**
3756
* Handles an incoming event from native
3857
* @param event
@@ -132,6 +151,13 @@ class DatabaseSyncTree {
132151
if (isString(registrations)) {
133152
this.removeRegistration(registrations);
134153
SharedEventEmitter.removeAllListeners(registrations);
154+
155+
// mirror upstream accounting - clear out all registrations for this key
156+
if (registrations == null) {
157+
this._registry = {};
158+
} else {
159+
delete this._registry[registrations];
160+
}
135161
return 1;
136162
}
137163

@@ -141,6 +167,12 @@ class DatabaseSyncTree {
141167
for (let i = 0, len = registrations.length; i < len; i++) {
142168
this.removeRegistration(registrations[i]);
143169
SharedEventEmitter.removeAllListeners(registrations[i]);
170+
// mirror upstream accounting - clear out all registrations for this key
171+
if (registrations[i] == null) {
172+
this._registry = {};
173+
} else {
174+
delete this._registry[registrations[i]];
175+
}
144176
}
145177

146178
return registrations.length;
@@ -163,15 +195,10 @@ class DatabaseSyncTree {
163195
const registration = registrations[i];
164196
let subscriptions;
165197

166-
// EventEmitter in react-native < 0.70 had a `_subscriber` property with a method for subscriptions by type...
167-
if (SharedEventEmitter._subscriber) {
168-
subscriptions = SharedEventEmitter._subscriber.getSubscriptionsForType(registration);
169-
} else {
170-
// ...react-native 0.70 now stores subscribers as a map of Sets by type in `_registry`
171-
const registrySubscriptionsSet = SharedEventEmitter._registry[registration];
172-
if (registrySubscriptionsSet) {
173-
subscriptions = Array.from(registrySubscriptionsSet);
174-
}
198+
// get all registrations for this key so we can find our specific listener
199+
const registrySubscriptionsSet = this._registry[registration];
200+
if (registrySubscriptionsSet) {
201+
subscriptions = Array.from(registrySubscriptionsSet);
175202
}
176203

177204
if (subscriptions) {
@@ -180,6 +207,7 @@ class DatabaseSyncTree {
180207
// The subscription may have been removed during this event loop.
181208
// its listener matches the listener in method parameters
182209
if (subscription && subscription.listener === listener) {
210+
this._registry[registration].delete(subscription);
183211
subscription.remove();
184212
removed.push(registration);
185213
this.removeRegistration(registration);
@@ -278,7 +306,12 @@ class DatabaseSyncTree {
278306
subscription.remove();
279307
});
280308
} else {
281-
SharedEventEmitter.addListener(eventRegistrationKey, listener);
309+
const registration = SharedEventEmitter.addListener(eventRegistrationKey, listener);
310+
311+
// add this listener registration info to our emitter-key map
312+
// in case we need to identify and remove a specific listener later
313+
const registrations = this._allocate(this._registry, eventRegistrationKey);
314+
registrations.add(registration);
282315
}
283316

284317
return eventRegistrationKey;

0 commit comments

Comments
 (0)