Add new `forkEvent`/`unforkEvent` API

Reviewed By: vjeux

Differential Revision: D4648427

fbshipit-source-id: 9bbbd81f49a9363ac271b3906d73f937f0d1f500
This commit is contained in:
Spencer Ahrens 2017-03-06 21:42:33 -08:00 committed by Facebook Github Bot
parent b7e9374c64
commit 5257c35d05
2 changed files with 61 additions and 7 deletions

View File

@ -2192,9 +2192,29 @@ function attachNativeEvent(viewRef: any, eventName: string, argMapping: Array<?M
};
}
function forkEvent(event: ?AnimatedEvent | ?Function, listener: Function): AnimatedEvent | Function {
if (!event) {
return listener;
} else if (event instanceof AnimatedEvent) {
event.__addListener(listener);
return event;
} else {
return (...args) => {
typeof event === 'function' && event(...args);
listener(...args);
};
}
}
function unforkEvent(event: ?AnimatedEvent | ?Function, listener: Function): void {
if (event && event instanceof AnimatedEvent) {
event.__removeListener(listener);
}
}
class AnimatedEvent {
_argMapping: Array<?Mapping>;
_listener: ?Function;
_listeners: Array<Function> = [];
_attachedEvent: ?{
detach: () => void,
};
@ -2205,7 +2225,9 @@ class AnimatedEvent {
config?: EventConfig = {}
) {
this._argMapping = argMapping;
this._listener = config.listener;
if (config.listener) {
this.__addListener(config.listener);
}
this._attachedEvent = null;
this.__isNative = shouldUseNativeDriver(config);
@ -2214,6 +2236,14 @@ class AnimatedEvent {
}
}
__addListener(callback: Function): void {
this._listeners.push(callback);
}
__removeListener(callback: Function): void {
this._listeners = this._listeners.filter((listener) => listener !== callback);
}
__attach(viewRef, eventName) {
invariant(this.__isNative, 'Only native driven events need to be attached.');
@ -2228,7 +2258,7 @@ class AnimatedEvent {
__getHandler() {
if (this.__isNative) {
return this._listener;
return this._callListeners;
}
return (...args) => {
@ -2247,13 +2277,14 @@ class AnimatedEvent {
traverse(mapping, args[idx], 'arg' + idx);
});
}
if (this._listener) {
this._listener.apply(null, args);
}
this._callListeners(...args);
};
}
_callListeners = (...args) => {
this._listeners.forEach(listener => listener(...args));
};
_validateMapping() {
const traverse = (recMapping, recEvt, key) => {
if (typeof recEvt === 'number') {
@ -2602,5 +2633,12 @@ module.exports = {
*/
attachNativeEvent,
/**
* Advanced imperative API for snooping on animated events that are passed in through props. Use
* values directly where possible.
*/
forkEvent,
unforkEvent,
__PropsOnlyForTests: AnimatedProps,
};

View File

@ -353,6 +353,22 @@ describe('Animated tests', () => {
expect(listener.mock.calls.length).toBe(1);
expect(listener).toBeCalledWith({foo: 42});
});
it('should call forked event listeners', () => {
var value = new Animated.Value(0);
var listener = jest.fn();
var handler = Animated.event(
[{foo: value}],
{listener},
);
var listener2 = jest.fn();
var forkedHandler = Animated.forkEvent(handler, listener2);
forkedHandler({foo: 42});
expect(value.__getValue()).toBe(42);
expect(listener.mock.calls.length).toBe(1);
expect(listener).toBeCalledWith({foo: 42});
expect(listener2.mock.calls.length).toBe(1);
expect(listener2).toBeCalledWith({foo: 42});
});
});
describe('Animated Interactions', () => {