Skip to content

Commit

Permalink
Add new forkEvent/unforkEvent API
Browse files Browse the repository at this point in the history
Reviewed By: vjeux

Differential Revision: D4648427

fbshipit-source-id: 9bbbd81f49a9363ac271b3906d73f937f0d1f500
  • Loading branch information
sahrens authored and facebook-github-bot committed Mar 7, 2017
1 parent b7e9374 commit 5257c35
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 7 deletions.
52 changes: 45 additions & 7 deletions Libraries/Animated/src/AnimatedImplementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand All @@ -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);

Expand All @@ -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.');

Expand All @@ -2228,7 +2258,7 @@ class AnimatedEvent {

__getHandler() {
if (this.__isNative) {
return this._listener;
return this._callListeners;
}

return (...args) => {
Expand All @@ -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') {
Expand Down Expand Up @@ -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,
};
16 changes: 16 additions & 0 deletions Libraries/Animated/src/__tests__/Animated-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down

0 comments on commit 5257c35

Please sign in to comment.