mirror of
https://github.com/hanzoai/react.git
synced 2026-09-24 17:02:27 +00:00
Check for event listener in props instead of bank (#8192)
This just reads events from the props instead of storing them in a listener back. I had to rewrite a bunch of tests to cover this model. I removed the tests that just test the adding and removing over listeners since there is no equivalent behavior anymore.
This commit is contained in:
committed by
GitHub
parent
16d50c9521
commit
841259d49f
@@ -147,8 +147,6 @@ src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
|
||||
* should validate against invalid styles
|
||||
* should track input values
|
||||
* should track textarea values
|
||||
* should execute custom event plugin listening behavior
|
||||
* should handle null and missing properly with event hooks
|
||||
* should warn for children on void elements
|
||||
* should support custom elements which extend native elements
|
||||
* should warn against children for void elements
|
||||
@@ -157,7 +155,6 @@ src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
|
||||
* should warn about contentEditable and children
|
||||
* should validate against invalid styles
|
||||
* should report component containing invalid styles
|
||||
* should clean up listeners
|
||||
* should clean up input value tracking
|
||||
* should clean up input textarea tracking
|
||||
* should warn about the `onScroll` issue when unsupported (IE8)
|
||||
@@ -382,13 +379,11 @@ src/renderers/dom/stack/server/__tests__/ReactServerRendering-test.js
|
||||
* should generate simple markup for self-closing tags
|
||||
* should generate simple markup for attribute with `>` symbol
|
||||
* should generate comment markup for component returns null
|
||||
* should not register event listeners
|
||||
* should render composite components
|
||||
* should only execute certain lifecycle methods
|
||||
* should have the correct mounting behavior
|
||||
* should not put checksum and React ID on components
|
||||
* should not put checksum and React ID on text components
|
||||
* should not register event listeners
|
||||
* should only execute certain lifecycle methods
|
||||
* allows setState in componentWillMount without using DOM
|
||||
* renders components with different batching strategies
|
||||
@@ -503,6 +498,9 @@ src/renderers/shared/shared/__tests__/ReactTreeTraversal-test.js
|
||||
* should leave to the window
|
||||
* should leave to the window from the shallowest
|
||||
|
||||
src/renderers/shared/shared/event/__tests__/EventPluginHub-test.js
|
||||
* should prevent non-function listeners, at dispatch
|
||||
|
||||
src/renderers/shared/stack/reconciler/__tests__/ReactChildReconciler-test.js
|
||||
* warns for duplicated keys
|
||||
* warns for duplicated keys with component stack info
|
||||
|
||||
@@ -955,9 +955,6 @@ src/renderers/shared/shared/__tests__/ReactTreeTraversal-test.js
|
||||
* should not traverse if enter/leave the same node
|
||||
* should determine the first common ancestor correctly
|
||||
|
||||
src/renderers/shared/shared/event/__tests__/EventPluginHub-test.js
|
||||
* should prevent non-function listeners
|
||||
|
||||
src/renderers/shared/shared/event/__tests__/EventPluginRegistry-test.js
|
||||
* should be able to inject ordering before plugins
|
||||
* should be able to inject plugins before and after ordering
|
||||
@@ -1062,7 +1059,6 @@ src/renderers/shared/stack/reconciler/__tests__/ReactErrorBoundaries-test.js
|
||||
* propagates errors on retry on mounting
|
||||
* propagates errors inside boundary during componentWillMount
|
||||
* propagates errors inside boundary while rendering error state
|
||||
* does not register event handlers for unmounted children
|
||||
* does not call componentWillUnmount when aborting initial mount
|
||||
* resets refs if mounting aborts
|
||||
* successfully mounts if no error occurs
|
||||
|
||||
@@ -163,16 +163,6 @@ function getListeningForDocument(mountAt) {
|
||||
return alreadyListeningTo[mountAt[topListenersIDKey]];
|
||||
}
|
||||
|
||||
/**
|
||||
* `ReactBrowserEventEmitter` is used to attach top-level event listeners. For
|
||||
* example:
|
||||
*
|
||||
* EventPluginHub.putListener('myID', 'onClick', myFunction);
|
||||
*
|
||||
* This would allocate a "registration" of `('onClick', myFunction)` on 'myID'.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,8 +15,9 @@ var EventListener;
|
||||
var EventPluginHub;
|
||||
var EventPluginRegistry;
|
||||
var React;
|
||||
var ReactBrowserEventEmitter;
|
||||
var ReactDOM;
|
||||
var ReactDOMComponentTree;
|
||||
var ReactBrowserEventEmitter;
|
||||
var ReactTestUtils;
|
||||
var TapEventPlugin;
|
||||
|
||||
@@ -43,18 +44,17 @@ var GRANDPARENT;
|
||||
var PARENT;
|
||||
var CHILD;
|
||||
|
||||
var getListener;
|
||||
var putListener;
|
||||
var deleteAllListeners;
|
||||
|
||||
function registerSimpleTestHandler() {
|
||||
EventPluginHub.putListener(getInternal(CHILD), ON_CLICK_KEY, LISTENER);
|
||||
var listener = EventPluginHub.getListener(getInternal(CHILD), ON_CLICK_KEY);
|
||||
putListener(CHILD, ON_CLICK_KEY, LISTENER);
|
||||
var listener = getListener(CHILD, ON_CLICK_KEY);
|
||||
expect(listener).toEqual(LISTENER);
|
||||
return EventPluginHub.getListener(getInternal(CHILD), ON_CLICK_KEY);
|
||||
return getListener(CHILD, ON_CLICK_KEY);
|
||||
}
|
||||
|
||||
function getInternal(node) {
|
||||
return ReactDOMComponentTree.getInstanceFromNode(node);
|
||||
}
|
||||
|
||||
|
||||
describe('ReactBrowserEventEmitter', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModuleRegistry();
|
||||
@@ -63,18 +63,67 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
EventPluginHub = require('EventPluginHub');
|
||||
EventPluginRegistry = require('EventPluginRegistry');
|
||||
React = require('React');
|
||||
ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
|
||||
ReactDOM = require('ReactDOM');
|
||||
ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
|
||||
ReactTestUtils = require('ReactTestUtils');
|
||||
TapEventPlugin = require('TapEventPlugin');
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
<div ref={(c) => GRANDPARENT = c}>
|
||||
<div ref={(c) => PARENT = c}>
|
||||
<div ref={(c) => CHILD = c} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
var container = document.createElement('div');
|
||||
|
||||
var GRANDPARENT_PROPS = {};
|
||||
var PARENT_PROPS = {};
|
||||
var CHILD_PROPS = {};
|
||||
|
||||
function renderTree() {
|
||||
ReactDOM.render(
|
||||
<div ref={(c) => GRANDPARENT = c} {...GRANDPARENT_PROPS}>
|
||||
<div ref={(c) => PARENT = c} {...PARENT_PROPS}>
|
||||
<div ref={(c) => CHILD = c} {...CHILD_PROPS} />
|
||||
</div>
|
||||
</div>,
|
||||
container
|
||||
);
|
||||
}
|
||||
|
||||
renderTree();
|
||||
|
||||
getListener = function(node, eventName) {
|
||||
var inst = ReactDOMComponentTree.getInstanceFromNode(node);
|
||||
return EventPluginHub.getListener(
|
||||
inst,
|
||||
eventName
|
||||
);
|
||||
};
|
||||
putListener = function(node, eventName, listener) {
|
||||
switch (node) {
|
||||
case CHILD:
|
||||
CHILD_PROPS[eventName] = listener;
|
||||
break;
|
||||
case PARENT:
|
||||
PARENT_PROPS[eventName] = listener;
|
||||
break;
|
||||
case GRANDPARENT:
|
||||
GRANDPARENT_PROPS[eventName] = listener;
|
||||
break;
|
||||
}
|
||||
// Rerender with new event listeners
|
||||
renderTree();
|
||||
};
|
||||
deleteAllListeners = function(node) {
|
||||
switch (node) {
|
||||
case CHILD:
|
||||
CHILD_PROPS = {};
|
||||
break;
|
||||
case PARENT:
|
||||
PARENT_PROPS = {};
|
||||
break;
|
||||
case GRANDPARENT:
|
||||
GRANDPARENT_PROPS = {};
|
||||
break;
|
||||
}
|
||||
renderTree();
|
||||
};
|
||||
|
||||
idCallOrder = [];
|
||||
tapMoveThreshold = TapEventPlugin.tapMoveThreshold;
|
||||
@@ -85,20 +134,20 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
|
||||
it('should store a listener correctly', () => {
|
||||
registerSimpleTestHandler();
|
||||
var listener = EventPluginHub.getListener(getInternal(CHILD), ON_CLICK_KEY);
|
||||
var listener = getListener(CHILD, ON_CLICK_KEY);
|
||||
expect(listener).toBe(LISTENER);
|
||||
});
|
||||
|
||||
it('should retrieve a listener correctly', () => {
|
||||
registerSimpleTestHandler();
|
||||
var listener = EventPluginHub.getListener(getInternal(CHILD), ON_CLICK_KEY);
|
||||
var listener = getListener(CHILD, ON_CLICK_KEY);
|
||||
expect(listener).toEqual(LISTENER);
|
||||
});
|
||||
|
||||
it('should clear all handlers when asked to', () => {
|
||||
registerSimpleTestHandler();
|
||||
EventPluginHub.deleteAllListeners(getInternal(CHILD));
|
||||
var listener = EventPluginHub.getListener(getInternal(CHILD), ON_CLICK_KEY);
|
||||
deleteAllListeners(CHILD);
|
||||
var listener = getListener(CHILD, ON_CLICK_KEY);
|
||||
expect(listener).toBe(undefined);
|
||||
});
|
||||
|
||||
@@ -122,153 +171,153 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
);
|
||||
|
||||
it('should bubble simply', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
putListener(
|
||||
CHILD,
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(CHILD))
|
||||
recordID.bind(null, CHILD)
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
putListener(
|
||||
PARENT,
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(PARENT))
|
||||
recordID.bind(null, PARENT)
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(GRANDPARENT),
|
||||
putListener(
|
||||
GRANDPARENT,
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(GRANDPARENT))
|
||||
recordID.bind(null, GRANDPARENT)
|
||||
);
|
||||
ReactTestUtils.Simulate.click(CHILD);
|
||||
expect(idCallOrder.length).toBe(3);
|
||||
expect(idCallOrder[0]).toBe(getInternal(CHILD));
|
||||
expect(idCallOrder[1]).toBe(getInternal(PARENT));
|
||||
expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT));
|
||||
expect(idCallOrder[0]).toBe(CHILD);
|
||||
expect(idCallOrder[1]).toBe(PARENT);
|
||||
expect(idCallOrder[2]).toBe(GRANDPARENT);
|
||||
});
|
||||
|
||||
it('should continue bubbling if an error is thrown', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
putListener(
|
||||
CHILD,
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(CHILD))
|
||||
recordID.bind(null, CHILD)
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
putListener(
|
||||
PARENT,
|
||||
ON_CLICK_KEY,
|
||||
function() {
|
||||
recordID(getInternal(PARENT));
|
||||
recordID(PARENT);
|
||||
throw new Error('Handler interrupted');
|
||||
}
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(GRANDPARENT),
|
||||
putListener(
|
||||
GRANDPARENT,
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(GRANDPARENT))
|
||||
recordID.bind(null, GRANDPARENT)
|
||||
);
|
||||
expect(function() {
|
||||
ReactTestUtils.Simulate.click(CHILD);
|
||||
}).toThrow();
|
||||
expect(idCallOrder.length).toBe(3);
|
||||
expect(idCallOrder[0]).toBe(getInternal(CHILD));
|
||||
expect(idCallOrder[1]).toBe(getInternal(PARENT));
|
||||
expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT));
|
||||
expect(idCallOrder[0]).toBe(CHILD);
|
||||
expect(idCallOrder[1]).toBe(PARENT);
|
||||
expect(idCallOrder[2]).toBe(GRANDPARENT);
|
||||
});
|
||||
|
||||
it('should set currentTarget', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
putListener(
|
||||
CHILD,
|
||||
ON_CLICK_KEY,
|
||||
function(event) {
|
||||
recordID(getInternal(CHILD));
|
||||
recordID(CHILD);
|
||||
expect(event.currentTarget).toBe(CHILD);
|
||||
}
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
putListener(
|
||||
PARENT,
|
||||
ON_CLICK_KEY,
|
||||
function(event) {
|
||||
recordID(getInternal(PARENT));
|
||||
recordID(PARENT);
|
||||
expect(event.currentTarget).toBe(PARENT);
|
||||
}
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(GRANDPARENT),
|
||||
putListener(
|
||||
GRANDPARENT,
|
||||
ON_CLICK_KEY,
|
||||
function(event) {
|
||||
recordID(getInternal(GRANDPARENT));
|
||||
recordID(GRANDPARENT);
|
||||
expect(event.currentTarget).toBe(GRANDPARENT);
|
||||
}
|
||||
);
|
||||
ReactTestUtils.Simulate.click(CHILD);
|
||||
expect(idCallOrder.length).toBe(3);
|
||||
expect(idCallOrder[0]).toBe(getInternal(CHILD));
|
||||
expect(idCallOrder[1]).toBe(getInternal(PARENT));
|
||||
expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT));
|
||||
expect(idCallOrder[0]).toBe(CHILD);
|
||||
expect(idCallOrder[1]).toBe(PARENT);
|
||||
expect(idCallOrder[2]).toBe(GRANDPARENT);
|
||||
});
|
||||
|
||||
it('should support stopPropagation()', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
putListener(
|
||||
CHILD,
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(CHILD))
|
||||
recordID.bind(null, CHILD)
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
putListener(
|
||||
PARENT,
|
||||
ON_CLICK_KEY,
|
||||
recordIDAndStopPropagation.bind(null, getInternal(PARENT))
|
||||
recordIDAndStopPropagation.bind(null, PARENT)
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(GRANDPARENT),
|
||||
putListener(
|
||||
GRANDPARENT,
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(GRANDPARENT))
|
||||
recordID.bind(null, GRANDPARENT)
|
||||
);
|
||||
ReactTestUtils.Simulate.click(CHILD);
|
||||
expect(idCallOrder.length).toBe(2);
|
||||
expect(idCallOrder[0]).toBe(getInternal(CHILD));
|
||||
expect(idCallOrder[1]).toBe(getInternal(PARENT));
|
||||
expect(idCallOrder[0]).toBe(CHILD);
|
||||
expect(idCallOrder[1]).toBe(PARENT);
|
||||
});
|
||||
|
||||
it('should stop after first dispatch if stopPropagation', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
putListener(
|
||||
CHILD,
|
||||
ON_CLICK_KEY,
|
||||
recordIDAndStopPropagation.bind(null, getInternal(CHILD))
|
||||
recordIDAndStopPropagation.bind(null, CHILD)
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
putListener(
|
||||
PARENT,
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(PARENT))
|
||||
recordID.bind(null, PARENT)
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(GRANDPARENT),
|
||||
putListener(
|
||||
GRANDPARENT,
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(GRANDPARENT))
|
||||
recordID.bind(null, GRANDPARENT)
|
||||
);
|
||||
ReactTestUtils.Simulate.click(CHILD);
|
||||
expect(idCallOrder.length).toBe(1);
|
||||
expect(idCallOrder[0]).toBe(getInternal(CHILD));
|
||||
expect(idCallOrder[0]).toBe(CHILD);
|
||||
});
|
||||
|
||||
it('should not stopPropagation if false is returned', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
putListener(
|
||||
CHILD,
|
||||
ON_CLICK_KEY,
|
||||
recordIDAndReturnFalse.bind(null, getInternal(CHILD))
|
||||
recordIDAndReturnFalse.bind(null, CHILD)
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
putListener(
|
||||
PARENT,
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(PARENT))
|
||||
recordID.bind(null, PARENT)
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(GRANDPARENT),
|
||||
putListener(
|
||||
GRANDPARENT,
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(GRANDPARENT))
|
||||
recordID.bind(null, GRANDPARENT)
|
||||
);
|
||||
spyOn(console, 'error');
|
||||
ReactTestUtils.Simulate.click(CHILD);
|
||||
expect(idCallOrder.length).toBe(3);
|
||||
expect(idCallOrder[0]).toBe(getInternal(CHILD));
|
||||
expect(idCallOrder[1]).toBe(getInternal(PARENT));
|
||||
expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT));
|
||||
expect(idCallOrder[0]).toBe(CHILD);
|
||||
expect(idCallOrder[1]).toBe(PARENT);
|
||||
expect(idCallOrder[2]).toBe(GRANDPARENT);
|
||||
expect(console.error.calls.count()).toEqual(0);
|
||||
});
|
||||
|
||||
@@ -284,15 +333,15 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
it('should invoke handlers that were removed while bubbling', () => {
|
||||
var handleParentClick = jest.fn();
|
||||
var handleChildClick = function(event) {
|
||||
EventPluginHub.deleteAllListeners(getInternal(PARENT));
|
||||
deleteAllListeners(PARENT);
|
||||
};
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
putListener(
|
||||
CHILD,
|
||||
ON_CLICK_KEY,
|
||||
handleChildClick
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
putListener(
|
||||
PARENT,
|
||||
ON_CLICK_KEY,
|
||||
handleParentClick
|
||||
);
|
||||
@@ -303,14 +352,14 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
it('should not invoke newly inserted handlers while bubbling', () => {
|
||||
var handleParentClick = jest.fn();
|
||||
var handleChildClick = function(event) {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
putListener(
|
||||
PARENT,
|
||||
ON_CLICK_KEY,
|
||||
handleParentClick
|
||||
);
|
||||
};
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
putListener(
|
||||
CHILD,
|
||||
ON_CLICK_KEY,
|
||||
handleChildClick
|
||||
);
|
||||
@@ -319,21 +368,21 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
});
|
||||
|
||||
it('should have mouse enter simulated by test utils', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
putListener(
|
||||
CHILD,
|
||||
ON_MOUSE_ENTER_KEY,
|
||||
recordID.bind(null, getInternal(CHILD))
|
||||
recordID.bind(null, CHILD)
|
||||
);
|
||||
ReactTestUtils.Simulate.mouseEnter(CHILD);
|
||||
expect(idCallOrder.length).toBe(1);
|
||||
expect(idCallOrder[0]).toBe(getInternal(CHILD));
|
||||
expect(idCallOrder[0]).toBe(CHILD);
|
||||
});
|
||||
|
||||
it('should infer onTouchTap from a touchStart/End', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
putListener(
|
||||
CHILD,
|
||||
ON_TOUCH_TAP_KEY,
|
||||
recordID.bind(null, getInternal(CHILD))
|
||||
recordID.bind(null, CHILD)
|
||||
);
|
||||
ReactTestUtils.SimulateNative.touchStart(
|
||||
CHILD,
|
||||
@@ -344,14 +393,14 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
ReactTestUtils.nativeTouchData(0, 0)
|
||||
);
|
||||
expect(idCallOrder.length).toBe(1);
|
||||
expect(idCallOrder[0]).toBe(getInternal(CHILD));
|
||||
expect(idCallOrder[0]).toBe(CHILD);
|
||||
});
|
||||
|
||||
it('should infer onTouchTap from when dragging below threshold', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
putListener(
|
||||
CHILD,
|
||||
ON_TOUCH_TAP_KEY,
|
||||
recordID.bind(null, getInternal(CHILD))
|
||||
recordID.bind(null, CHILD)
|
||||
);
|
||||
ReactTestUtils.SimulateNative.touchStart(
|
||||
CHILD,
|
||||
@@ -362,14 +411,14 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
ReactTestUtils.nativeTouchData(0, tapMoveThreshold - 1)
|
||||
);
|
||||
expect(idCallOrder.length).toBe(1);
|
||||
expect(idCallOrder[0]).toBe(getInternal(CHILD));
|
||||
expect(idCallOrder[0]).toBe(CHILD);
|
||||
});
|
||||
|
||||
it('should not onTouchTap from when dragging beyond threshold', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
putListener(
|
||||
CHILD,
|
||||
ON_TOUCH_TAP_KEY,
|
||||
recordID.bind(null, getInternal(CHILD))
|
||||
recordID.bind(null, CHILD)
|
||||
);
|
||||
ReactTestUtils.SimulateNative.touchStart(
|
||||
CHILD,
|
||||
@@ -423,20 +472,20 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
});
|
||||
|
||||
it('should bubble onTouchTap', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
putListener(
|
||||
CHILD,
|
||||
ON_TOUCH_TAP_KEY,
|
||||
recordID.bind(null, getInternal(CHILD))
|
||||
recordID.bind(null, CHILD)
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
putListener(
|
||||
PARENT,
|
||||
ON_TOUCH_TAP_KEY,
|
||||
recordID.bind(null, getInternal(PARENT))
|
||||
recordID.bind(null, PARENT)
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(GRANDPARENT),
|
||||
putListener(
|
||||
GRANDPARENT,
|
||||
ON_TOUCH_TAP_KEY,
|
||||
recordID.bind(null, getInternal(GRANDPARENT))
|
||||
recordID.bind(null, GRANDPARENT)
|
||||
);
|
||||
ReactTestUtils.SimulateNative.touchStart(
|
||||
CHILD,
|
||||
@@ -447,9 +496,9 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
ReactTestUtils.nativeTouchData(0, 0)
|
||||
);
|
||||
expect(idCallOrder.length).toBe(3);
|
||||
expect(idCallOrder[0]).toBe(getInternal(CHILD));
|
||||
expect(idCallOrder[1]).toBe(getInternal(PARENT));
|
||||
expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT));
|
||||
expect(idCallOrder[0]).toBe(CHILD);
|
||||
expect(idCallOrder[1]).toBe(PARENT);
|
||||
expect(idCallOrder[2]).toBe(GRANDPARENT);
|
||||
});
|
||||
|
||||
it('should not crash ensureScrollValueMonitoring when createEvent returns null', () => {
|
||||
|
||||
@@ -972,61 +972,6 @@ describe('ReactDOMComponent', () => {
|
||||
expect(tracker.getValue()).toEqual('foo');
|
||||
});
|
||||
|
||||
it('should execute custom event plugin listening behavior', () => {
|
||||
var SimpleEventPlugin = require('SimpleEventPlugin');
|
||||
|
||||
SimpleEventPlugin.didPutListener = jest.fn();
|
||||
SimpleEventPlugin.willDeleteListener = jest.fn();
|
||||
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(
|
||||
<div onClick={() => true} />,
|
||||
container
|
||||
);
|
||||
|
||||
expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(1);
|
||||
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
|
||||
expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should handle null and missing properly with event hooks', () => {
|
||||
var SimpleEventPlugin = require('SimpleEventPlugin');
|
||||
|
||||
SimpleEventPlugin.didPutListener = jest.fn();
|
||||
SimpleEventPlugin.willDeleteListener = jest.fn();
|
||||
var container = document.createElement('div');
|
||||
|
||||
ReactDOM.render(<div onClick={false} />, container);
|
||||
expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(0);
|
||||
expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(0);
|
||||
|
||||
ReactDOM.render(<div onClick={null} />, container);
|
||||
expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(0);
|
||||
expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(0);
|
||||
|
||||
ReactDOM.render(<div onClick={() => 'apple'} />, container);
|
||||
expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(1);
|
||||
expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(0);
|
||||
|
||||
ReactDOM.render(<div onClick={() => 'banana'} />, container);
|
||||
expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(2);
|
||||
expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(0);
|
||||
|
||||
ReactDOM.render(<div onClick={null} />, container);
|
||||
expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(2);
|
||||
expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(1);
|
||||
|
||||
ReactDOM.render(<div />, container);
|
||||
expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(2);
|
||||
expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(1);
|
||||
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(2);
|
||||
expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should warn for children on void elements', () => {
|
||||
class X extends React.Component {
|
||||
render() {
|
||||
@@ -1157,31 +1102,6 @@ describe('ReactDOMComponent', () => {
|
||||
});
|
||||
|
||||
describe('unmountComponent', () => {
|
||||
it('should clean up listeners', () => {
|
||||
var EventPluginHub = require('EventPluginHub');
|
||||
var ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
|
||||
var container = document.createElement('div');
|
||||
document.body.appendChild(container);
|
||||
|
||||
var callback = function() {};
|
||||
var instance = <div onClick={callback} />;
|
||||
instance = ReactDOM.render(instance, container);
|
||||
|
||||
var rootNode = ReactDOM.findDOMNode(instance);
|
||||
var inst = ReactDOMComponentTree.getInstanceFromNode(rootNode);
|
||||
expect(
|
||||
EventPluginHub.getListener(inst, 'onClick')
|
||||
).toBe(callback);
|
||||
expect(rootNode).toBe(ReactDOM.findDOMNode(instance));
|
||||
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
|
||||
expect(
|
||||
EventPluginHub.getListener(inst, 'onClick')
|
||||
).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should clean up input value tracking', () => {
|
||||
var container = document.createElement('div');
|
||||
var node = ReactDOM.render(<input type="text" defaultValue="foo"/>, container);
|
||||
|
||||
@@ -19,7 +19,6 @@ var DOMLazyTree = require('DOMLazyTree');
|
||||
var DOMNamespaces = require('DOMNamespaces');
|
||||
var DOMProperty = require('DOMProperty');
|
||||
var DOMPropertyOperations = require('DOMPropertyOperations');
|
||||
var EventPluginHub = require('EventPluginHub');
|
||||
var EventPluginRegistry = require('EventPluginRegistry');
|
||||
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
|
||||
var ReactDOMComponentFlags = require('ReactDOMComponentFlags');
|
||||
@@ -43,7 +42,6 @@ var warning = require('warning');
|
||||
var didWarnShadyDOM = false;
|
||||
|
||||
var Flags = ReactDOMComponentFlags;
|
||||
var deleteListener = EventPluginHub.deleteListener;
|
||||
var getNode = ReactDOMComponentTree.getNodeFromInstance;
|
||||
var listenTo = ReactBrowserEventEmitter.listenTo;
|
||||
var registrationNameModules = EventPluginRegistry.registrationNameModules;
|
||||
@@ -205,30 +203,6 @@ function assertValidProps(component, props) {
|
||||
);
|
||||
}
|
||||
|
||||
function enqueuePutListener(inst, registrationName, listener, transaction) {
|
||||
if (transaction instanceof ReactServerRenderingTransaction) {
|
||||
return;
|
||||
}
|
||||
if (__DEV__) {
|
||||
// IE8 has no API for event capturing and the `onScroll` event doesn't
|
||||
// bubble.
|
||||
warning(
|
||||
registrationName !== 'onScroll' || isEventSupported('scroll', true),
|
||||
'This browser doesn\'t support the `onScroll` event'
|
||||
);
|
||||
}
|
||||
var containerInfo = inst._hostContainerInfo;
|
||||
var isDocumentFragment = containerInfo._node && containerInfo._node.nodeType === DOC_FRAGMENT_TYPE;
|
||||
var doc = isDocumentFragment ? containerInfo._node : containerInfo._ownerDocument;
|
||||
listenTo(registrationName, doc);
|
||||
transaction.getReactMountReady().enqueue(putListener, {
|
||||
inst: inst,
|
||||
registrationName: registrationName,
|
||||
listener: listener,
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: This is coming from future #8192. Dedupe this and enqueuePutListener.
|
||||
function ensureListeningTo(inst, registrationName, transaction) {
|
||||
if (transaction instanceof ReactServerRenderingTransaction) {
|
||||
return;
|
||||
@@ -247,15 +221,6 @@ function ensureListeningTo(inst, registrationName, transaction) {
|
||||
listenTo(registrationName, doc);
|
||||
}
|
||||
|
||||
function putListener() {
|
||||
var listenerToPut = this;
|
||||
EventPluginHub.putListener(
|
||||
listenerToPut.inst,
|
||||
listenerToPut.registrationName,
|
||||
listenerToPut.listener
|
||||
);
|
||||
}
|
||||
|
||||
function inputPostMount() {
|
||||
var inst = this;
|
||||
ReactDOMInput.postMountWrapper(inst);
|
||||
@@ -792,7 +757,7 @@ ReactDOMComponent.Mixin = {
|
||||
}
|
||||
if (registrationNameModules.hasOwnProperty(propKey)) {
|
||||
if (propValue) {
|
||||
enqueuePutListener(this, propKey, propValue, transaction);
|
||||
ensureListeningTo(this, propKey, transaction);
|
||||
}
|
||||
} else {
|
||||
if (propKey === STYLE) {
|
||||
@@ -1047,12 +1012,7 @@ ReactDOMComponent.Mixin = {
|
||||
}
|
||||
this._previousStyleCopy = null;
|
||||
} else if (registrationNameModules.hasOwnProperty(propKey)) {
|
||||
if (lastProps[propKey]) {
|
||||
// Only call deleteListener if there was a listener previously or
|
||||
// else willDeleteListener gets called when there wasn't actually a
|
||||
// listener (e.g., onClick={null})
|
||||
deleteListener(this, propKey);
|
||||
}
|
||||
// Do nothing for event names.
|
||||
} else if (isCustomComponent(this._tag, lastProps)) {
|
||||
if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
|
||||
DOMPropertyOperations.deleteValueForAttribute(
|
||||
@@ -1113,9 +1073,7 @@ ReactDOMComponent.Mixin = {
|
||||
}
|
||||
} else if (registrationNameModules.hasOwnProperty(propKey)) {
|
||||
if (nextProp) {
|
||||
enqueuePutListener(this, propKey, nextProp, transaction);
|
||||
} else if (lastProp) {
|
||||
deleteListener(this, propKey);
|
||||
ensureListeningTo(this, propKey, transaction);
|
||||
}
|
||||
} else if (isCustomComponentTag) {
|
||||
if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
|
||||
@@ -1264,7 +1222,6 @@ ReactDOMComponent.Mixin = {
|
||||
|
||||
this.unmountChildren(safely, skipLifecycle);
|
||||
ReactDOMComponentTree.uncacheNode(this);
|
||||
EventPluginHub.deleteAllListeners(this);
|
||||
this._rootNodeID = 0;
|
||||
this._domID = 0;
|
||||
this._wrapperState = null;
|
||||
|
||||
@@ -85,15 +85,7 @@ describe('ReactServerRendering', () => {
|
||||
expect(response).toBe('<!-- react-empty: 1 -->');
|
||||
});
|
||||
|
||||
it('should not register event listeners', () => {
|
||||
var EventPluginHub = require('EventPluginHub');
|
||||
var cb = jest.fn();
|
||||
|
||||
ReactServerRendering.renderToString(
|
||||
<span onClick={cb}>hello world</span>
|
||||
);
|
||||
expect(EventPluginHub.__getListenerBank()).toEqual({});
|
||||
});
|
||||
// TODO: Test that listeners are not registered onto any document/container.
|
||||
|
||||
it('should render composite components', () => {
|
||||
class Parent extends React.Component {
|
||||
@@ -322,16 +314,6 @@ describe('ReactServerRendering', () => {
|
||||
expect(response).toBe('<span>hello world</span>');
|
||||
});
|
||||
|
||||
it('should not register event listeners', () => {
|
||||
var EventPluginHub = require('EventPluginHub');
|
||||
var cb = jest.fn();
|
||||
|
||||
ReactServerRendering.renderToStaticMarkup(
|
||||
<span onClick={cb}>hello world</span>
|
||||
);
|
||||
expect(EventPluginHub.__getListenerBank()).toEqual({});
|
||||
});
|
||||
|
||||
it('should only execute certain lifecycle methods', () => {
|
||||
function runTest() {
|
||||
var lifecycle = [];
|
||||
|
||||
@@ -14,18 +14,12 @@
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var ReactNativeAttributePayload = require('ReactNativeAttributePayload');
|
||||
var ReactNativeComponentTree = require('ReactNativeComponentTree');
|
||||
var ReactNativeEventEmitter = require('ReactNativeEventEmitter');
|
||||
var ReactNativeTagHandles = require('ReactNativeTagHandles');
|
||||
var ReactMultiChild = require('ReactMultiChild');
|
||||
var UIManager = require('UIManager');
|
||||
|
||||
var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
|
||||
|
||||
var registrationNames = ReactNativeEventEmitter.registrationNames;
|
||||
var putListener = ReactNativeEventEmitter.putListener;
|
||||
var deleteListener = ReactNativeEventEmitter.deleteListener;
|
||||
var deleteAllListeners = ReactNativeEventEmitter.deleteAllListeners;
|
||||
|
||||
type ReactNativeBaseComponentViewConfig = {
|
||||
validAttributes: Object;
|
||||
uiViewClassName: string;
|
||||
@@ -57,7 +51,6 @@ ReactNativeBaseComponent.Mixin = {
|
||||
|
||||
unmountComponent: function(safely, skipLifecycle) {
|
||||
ReactNativeComponentTree.uncacheNode(this);
|
||||
deleteAllListeners(this);
|
||||
this.unmountChildren(safely, skipLifecycle);
|
||||
this._rootNodeID = 0;
|
||||
},
|
||||
@@ -123,44 +116,9 @@ ReactNativeBaseComponent.Mixin = {
|
||||
);
|
||||
}
|
||||
|
||||
this._reconcileListenersUponUpdate(
|
||||
prevElement.props,
|
||||
nextElement.props
|
||||
);
|
||||
this.updateChildren(nextElement.props.children, transaction, context);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {object} initialProps Native component props.
|
||||
*/
|
||||
_registerListenersUponCreation: function(initialProps) {
|
||||
for (var key in initialProps) {
|
||||
// NOTE: The check for `!props[key]`, is only possible because this method
|
||||
// registers listeners the *first* time a component is created.
|
||||
if (registrationNames[key] && initialProps[key]) {
|
||||
var listener = initialProps[key];
|
||||
putListener(this, key, listener);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Reconciles event listeners, adding or removing if necessary.
|
||||
* @param {object} prevProps Native component props including events.
|
||||
* @param {object} nextProps Next native component props including events.
|
||||
*/
|
||||
_reconcileListenersUponUpdate: function(prevProps, nextProps) {
|
||||
for (var key in nextProps) {
|
||||
if (registrationNames[key] && (nextProps[key] !== prevProps[key])) {
|
||||
if (nextProps[key]) {
|
||||
putListener(this, key, nextProps[key]);
|
||||
} else {
|
||||
deleteListener(this, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Currently this still uses IDs for reconciliation so this can return null.
|
||||
*
|
||||
@@ -207,7 +165,6 @@ ReactNativeBaseComponent.Mixin = {
|
||||
|
||||
ReactNativeComponentTree.precacheNode(this, tag);
|
||||
|
||||
this._registerListenersUponCreation(this._currentElement.props);
|
||||
this.initializeChildren(
|
||||
this._currentElement.props.children,
|
||||
tag,
|
||||
|
||||
@@ -78,29 +78,14 @@ var removeTouchesAtIndices = function(
|
||||
return rippedOut;
|
||||
};
|
||||
|
||||
/**
|
||||
* `ReactNativeEventEmitter` is used to attach top-level event listeners. For example:
|
||||
*
|
||||
* ReactNativeEventEmitter.putListener('myID', 'onClick', myFunction);
|
||||
*
|
||||
* This would allocate a "registration" of `('onClick', myFunction)` on 'myID'.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
var ReactNativeEventEmitter = {
|
||||
|
||||
...ReactEventEmitterMixin,
|
||||
|
||||
registrationNames: EventPluginRegistry.registrationNameModules,
|
||||
|
||||
putListener: EventPluginHub.putListener,
|
||||
|
||||
getListener: EventPluginHub.getListener,
|
||||
|
||||
deleteListener: EventPluginHub.deleteListener,
|
||||
|
||||
deleteAllListeners: EventPluginHub.deleteAllListeners,
|
||||
|
||||
/**
|
||||
* Internal version of `receiveEvent` in terms of normalized (non-tag)
|
||||
* `rootNodeID`.
|
||||
|
||||
@@ -19,11 +19,6 @@ var accumulateInto = require('accumulateInto');
|
||||
var forEachAccumulated = require('forEachAccumulated');
|
||||
var invariant = require('invariant');
|
||||
|
||||
/**
|
||||
* Internal store for event listeners
|
||||
*/
|
||||
var listenerBank = {};
|
||||
|
||||
/**
|
||||
* Internal queue of events that have accumulated their dispatches and are
|
||||
* waiting to have their dispatches executed.
|
||||
@@ -53,12 +48,6 @@ var executeDispatchesAndReleaseTopLevel = function(e) {
|
||||
return executeDispatchesAndRelease(e, false);
|
||||
};
|
||||
|
||||
var getDictionaryKey = function(inst) {
|
||||
// Prevents V8 performance issue:
|
||||
// https://github.com/facebook/react/pull/7232
|
||||
return '.' + inst._rootNodeID;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a unified interface for event plugins to be installed and configured.
|
||||
*
|
||||
@@ -101,88 +90,22 @@ var EventPluginHub = {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Stores `listener` at `listenerBank[registrationName][key]`. Is idempotent.
|
||||
*
|
||||
* @param {object} inst The instance, which is the source of events.
|
||||
* @param {string} registrationName Name of listener (e.g. `onClick`).
|
||||
* @param {function} listener The callback to store.
|
||||
*/
|
||||
putListener: function(inst, registrationName, listener) {
|
||||
invariant(
|
||||
typeof listener === 'function',
|
||||
'Expected %s listener to be a function, instead got type %s',
|
||||
registrationName, typeof listener
|
||||
);
|
||||
|
||||
var key = getDictionaryKey(inst);
|
||||
var bankForRegistrationName =
|
||||
listenerBank[registrationName] || (listenerBank[registrationName] = {});
|
||||
bankForRegistrationName[key] = listener;
|
||||
|
||||
var PluginModule =
|
||||
EventPluginRegistry.registrationNameModules[registrationName];
|
||||
if (PluginModule && PluginModule.didPutListener) {
|
||||
PluginModule.didPutListener(inst, registrationName, listener);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {object} inst The instance, which is the source of events.
|
||||
* @param {string} registrationName Name of listener (e.g. `onClick`).
|
||||
* @return {?function} The stored callback.
|
||||
*/
|
||||
getListener: function(inst, registrationName) {
|
||||
var bankForRegistrationName = listenerBank[registrationName];
|
||||
var key = getDictionaryKey(inst);
|
||||
return bankForRegistrationName && bankForRegistrationName[key];
|
||||
},
|
||||
|
||||
/**
|
||||
* Deletes a listener from the registration bank.
|
||||
*
|
||||
* @param {object} inst The instance, which is the source of events.
|
||||
* @param {string} registrationName Name of listener (e.g. `onClick`).
|
||||
*/
|
||||
deleteListener: function(inst, registrationName) {
|
||||
var PluginModule =
|
||||
EventPluginRegistry.registrationNameModules[registrationName];
|
||||
if (PluginModule && PluginModule.willDeleteListener) {
|
||||
PluginModule.willDeleteListener(inst, registrationName);
|
||||
}
|
||||
|
||||
var bankForRegistrationName = listenerBank[registrationName];
|
||||
// TODO: This should never be null -- when is it?
|
||||
if (bankForRegistrationName) {
|
||||
var key = getDictionaryKey(inst);
|
||||
delete bankForRegistrationName[key];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Deletes all listeners for the DOM element with the supplied ID.
|
||||
*
|
||||
* @param {object} inst The instance, which is the source of events.
|
||||
*/
|
||||
deleteAllListeners: function(inst) {
|
||||
var key = getDictionaryKey(inst);
|
||||
for (var registrationName in listenerBank) {
|
||||
if (!listenerBank.hasOwnProperty(registrationName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!listenerBank[registrationName][key]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var PluginModule =
|
||||
EventPluginRegistry.registrationNameModules[registrationName];
|
||||
if (PluginModule && PluginModule.willDeleteListener) {
|
||||
PluginModule.willDeleteListener(inst, registrationName);
|
||||
}
|
||||
|
||||
delete listenerBank[registrationName][key];
|
||||
var listener = inst._currentElement.props[registrationName];
|
||||
if (listener !== undefined) {
|
||||
invariant(
|
||||
typeof listener === 'function',
|
||||
'Expected %s listener to be a function, instead got type %s',
|
||||
registrationName,
|
||||
typeof listener
|
||||
);
|
||||
}
|
||||
return listener;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -260,17 +183,6 @@ var EventPluginHub = {
|
||||
ReactErrorUtils.rethrowCaughtError();
|
||||
},
|
||||
|
||||
/**
|
||||
* These are needed for tests only. Do not use!
|
||||
*/
|
||||
__purge: function() {
|
||||
listenerBank = {};
|
||||
},
|
||||
|
||||
__getListenerBank: function() {
|
||||
return listenerBank;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = EventPluginHub;
|
||||
|
||||
@@ -130,8 +130,7 @@ function publishEventForPlugin(
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes a registration name that is used to identify dispatched events and
|
||||
* can be used with `EventPluginHub.putListener` to register listeners.
|
||||
* Publishes a registration name that is used to identify dispatched events.
|
||||
*
|
||||
* @param {string} registrationName Registration name to add.
|
||||
* @param {object} PluginModule Plugin publishing the event.
|
||||
|
||||
@@ -36,14 +36,5 @@ export type PluginModule<NativeEvent> = {
|
||||
nativeTarget: NativeEvent,
|
||||
nativeEventTarget: EventTarget,
|
||||
) => null | ReactSyntheticEvent,
|
||||
didPutListener?: (
|
||||
inst: ReactInstance,
|
||||
registrationName: string,
|
||||
listener: () => void,
|
||||
) => void,
|
||||
willDeleteListener?: (
|
||||
inst: ReactInstance,
|
||||
registrationName: string,
|
||||
) => void,
|
||||
tapMoveThreshold?: number,
|
||||
};
|
||||
|
||||
@@ -14,19 +14,21 @@
|
||||
jest.mock('isEventSupported');
|
||||
|
||||
describe('EventPluginHub', () => {
|
||||
var EventPluginHub;
|
||||
var isEventSupported;
|
||||
var React;
|
||||
var ReactTestUtils;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModuleRegistry();
|
||||
EventPluginHub = require('EventPluginHub');
|
||||
isEventSupported = require('isEventSupported');
|
||||
isEventSupported.mockReturnValueOnce(false);
|
||||
React = require('React');
|
||||
ReactTestUtils = require('ReactTestUtils');
|
||||
});
|
||||
|
||||
it('should prevent non-function listeners', () => {
|
||||
it('should prevent non-function listeners, at dispatch', () => {
|
||||
var node = ReactTestUtils.renderIntoDocument(
|
||||
<div onClick="not a function" />
|
||||
);
|
||||
expect(function() {
|
||||
EventPluginHub.putListener(1, 'onClick', 'not a function');
|
||||
ReactTestUtils.SimulateNative.click(node);
|
||||
}).toThrowError(
|
||||
'Expected onClick listener to be a function, instead got type string'
|
||||
);
|
||||
|
||||
+38
-8
@@ -233,7 +233,7 @@ var registerTestHandlers = function(eventTestConfig, readableIDToID) {
|
||||
}
|
||||
return config.returnVal;
|
||||
}.bind(null, readableID, nodeConfig);
|
||||
EventPluginHub.putListener(getInstanceFromNode(id), registrationName, handler);
|
||||
putListener(getInstanceFromNode(id), registrationName, handler);
|
||||
}
|
||||
};
|
||||
for (var eventName in eventTestConfig) {
|
||||
@@ -258,9 +258,6 @@ var registerTestHandlers = function(eventTestConfig, readableIDToID) {
|
||||
return runs;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
var run = function(config, hierarchyConfig, nativeEventConfig) {
|
||||
var max = NA;
|
||||
var searchForMax = function(nodeConfig) {
|
||||
@@ -309,10 +306,30 @@ var PARENT_HOST_NODE = { };
|
||||
var CHILD_HOST_NODE = { };
|
||||
var CHILD_HOST_NODE2 = { };
|
||||
|
||||
var GRANDPARENT_INST = { _hostParent: null, _rootNodeID: '1', _hostNode: GRANDPARENT_HOST_NODE };
|
||||
var PARENT_INST = { _hostParent: GRANDPARENT_INST, _rootNodeID: '2', _hostNode: PARENT_HOST_NODE };
|
||||
var CHILD_INST = { _hostParent: PARENT_INST, _rootNodeID: '3', _hostNode: CHILD_HOST_NODE };
|
||||
var CHILD_INST2 = { _hostParent: PARENT_INST, _rootNodeID: '4', _hostNode: CHILD_HOST_NODE2 };
|
||||
var GRANDPARENT_INST = {
|
||||
_hostParent: null,
|
||||
_rootNodeID: '1',
|
||||
_hostNode: GRANDPARENT_HOST_NODE,
|
||||
_currentElement: { props: {} },
|
||||
};
|
||||
var PARENT_INST = {
|
||||
_hostParent: GRANDPARENT_INST,
|
||||
_rootNodeID: '2',
|
||||
_hostNode: PARENT_HOST_NODE,
|
||||
_currentElement: { props: {} },
|
||||
};
|
||||
var CHILD_INST = {
|
||||
_hostParent: PARENT_INST,
|
||||
_rootNodeID: '3',
|
||||
_hostNode: CHILD_HOST_NODE,
|
||||
_currentElement: { props: {} },
|
||||
};
|
||||
var CHILD_INST2 = {
|
||||
_hostParent: PARENT_INST,
|
||||
_rootNodeID: '4',
|
||||
_hostNode: CHILD_HOST_NODE2,
|
||||
_currentElement: { props: {} },
|
||||
};
|
||||
|
||||
GRANDPARENT_HOST_NODE._reactInstance = GRANDPARENT_INST;
|
||||
PARENT_HOST_NODE._reactInstance = PARENT_INST;
|
||||
@@ -339,6 +356,14 @@ function getNodeFromInstance(inst) {
|
||||
return inst._hostNode;
|
||||
}
|
||||
|
||||
function putListener(node, registrationName, handler) {
|
||||
node._currentElement.props[registrationName] = handler;
|
||||
}
|
||||
|
||||
function deleteAllListeners(node) {
|
||||
node._currentElement.props = {};
|
||||
}
|
||||
|
||||
describe('ResponderEventPlugin', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -348,6 +373,11 @@ describe('ResponderEventPlugin', () => {
|
||||
EventPluginUtils = require('EventPluginUtils');
|
||||
ResponderEventPlugin = require('ResponderEventPlugin');
|
||||
|
||||
deleteAllListeners(GRANDPARENT_INST);
|
||||
deleteAllListeners(PARENT_INST);
|
||||
deleteAllListeners(CHILD_INST);
|
||||
deleteAllListeners(CHILD_INST2);
|
||||
|
||||
EventPluginUtils.injection.injectComponentTree({
|
||||
getInstanceFromNode,
|
||||
getNodeFromInstance,
|
||||
|
||||
@@ -879,26 +879,6 @@ describe('ReactErrorBoundaries', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('does not register event handlers for unmounted children', () => {
|
||||
var EventPluginHub = require('EventPluginHub');
|
||||
var container = document.createElement('div');
|
||||
EventPluginHub.putListener = jest.fn();
|
||||
ReactDOM.render(
|
||||
<ErrorBoundary>
|
||||
<button onClick={() => {}}>Click me</button>
|
||||
<BrokenRender />
|
||||
</ErrorBoundary>,
|
||||
container
|
||||
);
|
||||
expect(EventPluginHub.putListener).not.toBeCalled();
|
||||
|
||||
log.length = 0;
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
expect(log).toEqual([
|
||||
'ErrorBoundary componentWillUnmount',
|
||||
]);
|
||||
});
|
||||
|
||||
it('does not call componentWillUnmount when aborting initial mount', () => {
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(
|
||||
|
||||
Reference in New Issue
Block a user