mirror of
https://github.com/zhigang1992/react-native-firebase.git
synced 2026-04-24 04:24:52 +08:00
[js][android] Support multiple listeners on a single ref
This commit is contained in:
@@ -10,6 +10,8 @@ import { ReferenceBase } from './../base';
|
||||
import { promisify, isFunction, isObject, tryJSONParse, tryJSONStringify, generatePushID } from './../../utils';
|
||||
|
||||
const FirebaseDatabase = NativeModules.RNFirebaseDatabase;
|
||||
// Unique Reference ID for native events
|
||||
let refId = 1;
|
||||
|
||||
/**
|
||||
* @link https://firebase.google.com/docs/reference/js/firebase.database.Reference
|
||||
@@ -17,15 +19,19 @@ const FirebaseDatabase = NativeModules.RNFirebaseDatabase;
|
||||
*/
|
||||
export default class Reference extends ReferenceBase {
|
||||
|
||||
refId: number;
|
||||
listeners: { [listenerId: number]: DatabaseListener };
|
||||
database: FirebaseDatabase;
|
||||
query: Query;
|
||||
|
||||
constructor(database: FirebaseDatabase, path: string, existingModifiers?: Array<string>) {
|
||||
constructor(database: FirebaseDatabase, path: string, existingModifiers?: Array<DatabaseModifier>) {
|
||||
super(database.firebase, path);
|
||||
this.refId = refId++;
|
||||
this.listeners = {};
|
||||
this.database = database;
|
||||
this.namespace = 'firebase:db:ref';
|
||||
this.query = new Query(this, path, existingModifiers);
|
||||
this.log.debug('Created new Reference', this.database._handle(path, existingModifiers));
|
||||
this.log.debug('Created new Reference', this.refId, this.path);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,7 +87,6 @@ export default class Reference extends ReferenceBase {
|
||||
|
||||
const path = this.path;
|
||||
const _value = this._serializeAnyType(value);
|
||||
|
||||
return promisify('push', FirebaseDatabase)(path, _value)
|
||||
.then(({ ref }) => {
|
||||
const newRef = new Reference(this.database, ref);
|
||||
@@ -95,36 +100,37 @@ export default class Reference extends ReferenceBase {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param eventType
|
||||
* @param eventName
|
||||
* @param successCallback
|
||||
* @param failureCallback
|
||||
* @param context TODO
|
||||
* @returns {*}
|
||||
*/
|
||||
on(eventType: string, successCallback: () => any, failureCallback: () => any) {
|
||||
on(eventName: string, successCallback: () => any, failureCallback: () => any) {
|
||||
if (!isFunction(successCallback)) throw new Error('The specified callback must be a function');
|
||||
if (failureCallback && !isFunction(failureCallback)) throw new Error('The specified error callback must be a function');
|
||||
const path = this.path;
|
||||
const modifiers = this.query.getModifiers();
|
||||
const modifiersString = this.query.getModifiersString();
|
||||
this.log.debug('adding reference.on', path, modifiersString, eventType);
|
||||
this.database.on(path, modifiersString, modifiers, eventType, successCallback, failureCallback);
|
||||
this.log.debug('adding reference.on', this.refId, eventName);
|
||||
const listener = {
|
||||
listenerId: Object.keys(this.listeners).length + 1,
|
||||
eventName,
|
||||
successCallback,
|
||||
failureCallback,
|
||||
};
|
||||
this.listeners[listener.listenerId] = listener;
|
||||
this.database.on(this, listener);
|
||||
return successCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param eventType
|
||||
* @param eventName
|
||||
* @param successCallback
|
||||
* @param failureCallback
|
||||
* @param context TODO
|
||||
* @returns {Promise.<TResult>}
|
||||
*/
|
||||
once(eventType: string = 'value', successCallback: (snapshot: Object) => void, failureCallback: (error: Error) => void) {
|
||||
const path = this.path;
|
||||
const modifiers = this.query.getModifiers();
|
||||
const modifiersString = this.query.getModifiersString();
|
||||
return promisify('once', FirebaseDatabase)(path, modifiersString, modifiers, eventType)
|
||||
once(eventName: string = 'value', successCallback: (snapshot: Object) => void, failureCallback: (error: FirebaseError) => void) {
|
||||
return promisify('once', FirebaseDatabase)(this.refId, this.path, this.query.getModifiers(), eventName)
|
||||
.then(({ snapshot }) => new Snapshot(this, snapshot))
|
||||
.then((snapshot) => {
|
||||
if (isFunction(successCallback)) successCallback(snapshot);
|
||||
@@ -139,15 +145,35 @@ export default class Reference extends ReferenceBase {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param eventType
|
||||
* @param eventName
|
||||
* @param origCB
|
||||
* @returns {*}
|
||||
*/
|
||||
off(eventType?: string = '', origCB?: () => any) {
|
||||
const path = this.path;
|
||||
const modifiersString = this.query.getModifiersString();
|
||||
this.log.debug('ref.off(): ', path, modifiersString, eventType);
|
||||
return this.database.off(path, modifiersString, eventType, origCB);
|
||||
off(eventName?: string = '', origCB?: () => any) {
|
||||
this.log.debug('ref.off(): ', this.refId, eventName);
|
||||
let listenersToRemove;
|
||||
if (eventName && origCB) {
|
||||
listenersToRemove = Object.values(this.listeners).filter((listener) => {
|
||||
return listener.eventName === eventName && listener.successCallback === origCB;
|
||||
});
|
||||
// Only remove a single listener as per the web spec
|
||||
if (listenersToRemove.length > 1) listenersToRemove = [listenersToRemove[0]];
|
||||
} else if (eventName) {
|
||||
listenersToRemove = Object.values(this.listeners).filter((listener) => {
|
||||
return listener.eventName === eventName;
|
||||
});
|
||||
} else if (origCB) {
|
||||
listenersToRemove = Object.values(this.listeners).filter((listener) => {
|
||||
return listener.successCallback === origCB;
|
||||
});
|
||||
} else {
|
||||
listenersToRemove = Object.values(this.listeners);
|
||||
}
|
||||
// Remove the listeners from the reference to prevent memory leaks
|
||||
listenersToRemove.forEach((listener) => {
|
||||
delete this.listeners[listener.listenerId];
|
||||
});
|
||||
return this.database.off(this.refId, listenersToRemove, Object.keys(this.listeners).length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,7 +253,7 @@ export default class Reference extends ReferenceBase {
|
||||
*/
|
||||
orderBy(name: string, key?: string): Reference {
|
||||
const newRef = new Reference(this.database, this.path, this.query.getModifiers());
|
||||
newRef.query.setOrderBy(name, key);
|
||||
newRef.query.orderBy(name, key);
|
||||
return newRef;
|
||||
}
|
||||
|
||||
@@ -261,7 +287,7 @@ export default class Reference extends ReferenceBase {
|
||||
*/
|
||||
limit(name: string, limit: number): Reference {
|
||||
const newRef = new Reference(this.database, this.path, this.query.getModifiers());
|
||||
newRef.query.setLimit(name, limit);
|
||||
newRef.query.limit(name, limit);
|
||||
return newRef;
|
||||
}
|
||||
|
||||
@@ -308,7 +334,7 @@ export default class Reference extends ReferenceBase {
|
||||
*/
|
||||
filter(name: string, value: any, key?: string): Reference {
|
||||
const newRef = new Reference(this.database, this.path, this.query.getModifiers());
|
||||
newRef.query.setFilter(name, value, key);
|
||||
newRef.query.filter(name, value, key);
|
||||
return newRef;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user