@samitouri / QOS-React / commits / dde670fd36

Reapply Check for event listener in props instead of bank (#8292)

* Reapply Check for event listener in props instead of bank (#8192) This reverts the previous revert. * Don't throw on falsy event listeners Some code relies on passing null. This restores the earlier behavior.

Sebastian Markbåge committed Nov 15, 2016 at 18:16 UTC dde670fd36d5f98769c54683fe04a63975f13247
15 files changed +248 -491
scripts/fiber/tests-failing.txt
+4 -5
@@ -103,8 +103,6 @@ src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
103 * should validate against invalid styles
104 * should track input values
105 * should track textarea values
106 -* should execute custom event plugin listening behavior
107 -* should handle null and missing properly with event hooks
106 * should warn for children on void elements
107 * should support custom elements which extend native elements
108 * should warn against children for void elements
@@ -112,7 +110,6 @@ src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
110 * should validate against multiple children props
111 * should validate against invalid styles
112 * should report component containing invalid styles
115 -* should clean up listeners
113 * should clean up input value tracking
114 * should clean up input textarea tracking
115 * should throw when an invalid tag name is used
@@ -289,13 +286,11 @@ src/renderers/dom/stack/server/__tests__/ReactServerRendering-test.js
286 * should generate simple markup for self-closing tags
287 * should generate simple markup for attribute with `>` symbol
288 * should generate comment markup for component returns null
292 -* should not register event listeners
289 * should render composite components
290 * should only execute certain lifecycle methods
291 * should have the correct mounting behavior
292 * should not put checksum and React ID on components
293 * should not put checksum and React ID on text components
298 -* should not register event listeners
294 * should only execute certain lifecycle methods
295 * allows setState in componentWillMount without using DOM
296 * renders components with different batching strategies
@@ -410,6 +405,10 @@ src/renderers/shared/shared/__tests__/ReactTreeTraversal-test.js
405 * should leave to the window
406 * should leave to the window from the shallowest
407
408 +src/renderers/shared/shared/event/__tests__/EventPluginHub-test.js
409 +* should prevent non-function listeners, at dispatch
410 +* should not prevent null listeners, at dispatch
411 +
412 src/renderers/shared/stack/reconciler/__tests__/ReactComponent-test.js
413 * should throw on invalid render targets
414 * should throw when supplying a ref outside of render method
scripts/fiber/tests-passing.txt
-4
@@ -962,9 +962,6 @@ src/renderers/shared/shared/__tests__/ReactTreeTraversal-test.js
962 * should not traverse if enter/leave the same node
963 * should determine the first common ancestor correctly
964
965 -src/renderers/shared/shared/event/__tests__/EventPluginHub-test.js
966 -* should prevent non-function listeners
967 -
965 src/renderers/shared/shared/event/__tests__/EventPluginRegistry-test.js
966 * should be able to inject ordering before plugins
967 * should be able to inject plugins before and after ordering
@@ -1077,7 +1074,6 @@ src/renderers/shared/stack/reconciler/__tests__/ReactErrorBoundaries-test.js
1074 * propagates errors on retry on mounting
1075 * propagates errors inside boundary during componentWillMount
1076 * propagates errors inside boundary while rendering error state
1080 -* does not register event handlers for unmounted children
1077 * does not call componentWillUnmount when aborting initial mount
1078 * resets refs if mounting aborts
1079 * successfully mounts if no error occurs
src/renderers/dom/shared/ReactBrowserEventEmitter.js
-10
@@ -163,16 +163,6 @@ function getListeningForDocument(mountAt) {
163 return alreadyListeningTo[mountAt[topListenersIDKey]];
164 }
165
166 -/**
167 - * `ReactBrowserEventEmitter` is used to attach top-level event listeners. For
168 - * example:
169 - *
170 - * EventPluginHub.putListener('myID', 'onClick', myFunction);
171 - *
172 - * This would allocate a "registration" of `('onClick', myFunction)` on 'myID'.
173 - *
174 - * @internal
175 - */
166 var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
167
168 /**
src/renderers/dom/shared/__tests__/ReactBrowserEventEmitter-test.js
+175 -126
@@ -15,8 +15,9 @@ var EventListener;
15 var EventPluginHub;
16 var EventPluginRegistry;
17 var React;
18 -var ReactBrowserEventEmitter;
18 +var ReactDOM;
19 var ReactDOMComponentTree;
20 +var ReactBrowserEventEmitter;
21 var ReactTestUtils;
22 var TapEventPlugin;
23
@@ -43,18 +44,17 @@ var GRANDPARENT;
44 var PARENT;
45 var CHILD;
46
47 +var getListener;
48 +var putListener;
49 +var deleteAllListeners;
50 +
51 function registerSimpleTestHandler() {
47 - EventPluginHub.putListener(getInternal(CHILD), ON_CLICK_KEY, LISTENER);
48 - var listener = EventPluginHub.getListener(getInternal(CHILD), ON_CLICK_KEY);
52 + putListener(CHILD, ON_CLICK_KEY, LISTENER);
53 + var listener = getListener(CHILD, ON_CLICK_KEY);
54 expect(listener).toEqual(LISTENER);
50 - return EventPluginHub.getListener(getInternal(CHILD), ON_CLICK_KEY);
51 -}
52 -
53 -function getInternal(node) {
54 - return ReactDOMComponentTree.getInstanceFromNode(node);
55 + return getListener(CHILD, ON_CLICK_KEY);
56 }
57
57 -
58 describe('ReactBrowserEventEmitter', () => {
59 beforeEach(() => {
60 jest.resetModuleRegistry();
@@ -63,18 +63,67 @@ describe('ReactBrowserEventEmitter', () => {
63 EventPluginHub = require('EventPluginHub');
64 EventPluginRegistry = require('EventPluginRegistry');
65 React = require('React');
66 - ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
66 + ReactDOM = require('ReactDOM');
67 ReactDOMComponentTree = require('ReactDOMComponentTree');
68 + ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
69 ReactTestUtils = require('ReactTestUtils');
70 TapEventPlugin = require('TapEventPlugin');
71
71 - ReactTestUtils.renderIntoDocument(
72 - <div ref={(c) => GRANDPARENT = c}>
73 - <div ref={(c) => PARENT = c}>
74 - <div ref={(c) => CHILD = c} />
75 - </div>
76 - </div>
77 - );
72 + var container = document.createElement('div');
73 +
74 + var GRANDPARENT_PROPS = {};
75 + var PARENT_PROPS = {};
76 + var CHILD_PROPS = {};
77 +
78 + function renderTree() {
79 + ReactDOM.render(
80 + <div ref={(c) => GRANDPARENT = c} {...GRANDPARENT_PROPS}>
81 + <div ref={(c) => PARENT = c} {...PARENT_PROPS}>
82 + <div ref={(c) => CHILD = c} {...CHILD_PROPS} />
83 + </div>
84 + </div>,
85 + container
86 + );
87 + }
88 +
89 + renderTree();
90 +
91 + getListener = function(node, eventName) {
92 + var inst = ReactDOMComponentTree.getInstanceFromNode(node);
93 + return EventPluginHub.getListener(
94 + inst,
95 + eventName
96 + );
97 + };
98 + putListener = function(node, eventName, listener) {
99 + switch (node) {
100 + case CHILD:
101 + CHILD_PROPS[eventName] = listener;
102 + break;
103 + case PARENT:
104 + PARENT_PROPS[eventName] = listener;
105 + break;
106 + case GRANDPARENT:
107 + GRANDPARENT_PROPS[eventName] = listener;
108 + break;
109 + }
110 + // Rerender with new event listeners
111 + renderTree();
112 + };
113 + deleteAllListeners = function(node) {
114 + switch (node) {
115 + case CHILD:
116 + CHILD_PROPS = {};
117 + break;
118 + case PARENT:
119 + PARENT_PROPS = {};
120 + break;
121 + case GRANDPARENT:
122 + GRANDPARENT_PROPS = {};
123 + break;
124 + }
125 + renderTree();
126 + };
127
128 idCallOrder = [];
129 tapMoveThreshold = TapEventPlugin.tapMoveThreshold;
@@ -85,20 +134,20 @@ describe('ReactBrowserEventEmitter', () => {
134
135 it('should store a listener correctly', () => {
136 registerSimpleTestHandler();
88 - var listener = EventPluginHub.getListener(getInternal(CHILD), ON_CLICK_KEY);
137 + var listener = getListener(CHILD, ON_CLICK_KEY);
138 expect(listener).toBe(LISTENER);
139 });
140
141 it('should retrieve a listener correctly', () => {
142 registerSimpleTestHandler();
94 - var listener = EventPluginHub.getListener(getInternal(CHILD), ON_CLICK_KEY);
143 + var listener = getListener(CHILD, ON_CLICK_KEY);
144 expect(listener).toEqual(LISTENER);
145 });
146
147 it('should clear all handlers when asked to', () => {
148 registerSimpleTestHandler();
100 - EventPluginHub.deleteAllListeners(getInternal(CHILD));
101 - var listener = EventPluginHub.getListener(getInternal(CHILD), ON_CLICK_KEY);
149 + deleteAllListeners(CHILD);
150 + var listener = getListener(CHILD, ON_CLICK_KEY);
151 expect(listener).toBe(undefined);
152 });
153
@@ -122,153 +171,153 @@ describe('ReactBrowserEventEmitter', () => {
171 );
172
173 it('should bubble simply', () => {
125 - EventPluginHub.putListener(
126 - getInternal(CHILD),
174 + putListener(
175 + CHILD,
176 ON_CLICK_KEY,
128 - recordID.bind(null, getInternal(CHILD))
177 + recordID.bind(null, CHILD)
178 );
130 - EventPluginHub.putListener(
131 - getInternal(PARENT),
179 + putListener(
180 + PARENT,
181 ON_CLICK_KEY,
133 - recordID.bind(null, getInternal(PARENT))
182 + recordID.bind(null, PARENT)
183 );
135 - EventPluginHub.putListener(
136 - getInternal(GRANDPARENT),
184 + putListener(
185 + GRANDPARENT,
186 ON_CLICK_KEY,
138 - recordID.bind(null, getInternal(GRANDPARENT))
187 + recordID.bind(null, GRANDPARENT)
188 );
189 ReactTestUtils.Simulate.click(CHILD);
190 expect(idCallOrder.length).toBe(3);
142 - expect(idCallOrder[0]).toBe(getInternal(CHILD));
143 - expect(idCallOrder[1]).toBe(getInternal(PARENT));
144 - expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT));
191 + expect(idCallOrder[0]).toBe(CHILD);
192 + expect(idCallOrder[1]).toBe(PARENT);
193 + expect(idCallOrder[2]).toBe(GRANDPARENT);
194 });
195
196 it('should continue bubbling if an error is thrown', () => {
148 - EventPluginHub.putListener(
149 - getInternal(CHILD),
197 + putListener(
198 + CHILD,
199 ON_CLICK_KEY,
151 - recordID.bind(null, getInternal(CHILD))
200 + recordID.bind(null, CHILD)
201 );
153 - EventPluginHub.putListener(
154 - getInternal(PARENT),
202 + putListener(
203 + PARENT,
204 ON_CLICK_KEY,
205 function() {
157 - recordID(getInternal(PARENT));
206 + recordID(PARENT);
207 throw new Error('Handler interrupted');
208 }
209 );
161 - EventPluginHub.putListener(
162 - getInternal(GRANDPARENT),
210 + putListener(
211 + GRANDPARENT,
212 ON_CLICK_KEY,
164 - recordID.bind(null, getInternal(GRANDPARENT))
213 + recordID.bind(null, GRANDPARENT)
214 );
215 expect(function() {
216 ReactTestUtils.Simulate.click(CHILD);
217 }).toThrow();
218 expect(idCallOrder.length).toBe(3);
170 - expect(idCallOrder[0]).toBe(getInternal(CHILD));
171 - expect(idCallOrder[1]).toBe(getInternal(PARENT));
172 - expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT));
219 + expect(idCallOrder[0]).toBe(CHILD);
220 + expect(idCallOrder[1]).toBe(PARENT);
221 + expect(idCallOrder[2]).toBe(GRANDPARENT);
222 });
223
224 it('should set currentTarget', () => {
176 - EventPluginHub.putListener(
177 - getInternal(CHILD),
225 + putListener(
226 + CHILD,
227 ON_CLICK_KEY,
228 function(event) {
180 - recordID(getInternal(CHILD));
229 + recordID(CHILD);
230 expect(event.currentTarget).toBe(CHILD);
231 }
232 );
184 - EventPluginHub.putListener(
185 - getInternal(PARENT),
233 + putListener(
234 + PARENT,
235 ON_CLICK_KEY,
236 function(event) {
188 - recordID(getInternal(PARENT));
237 + recordID(PARENT);
238 expect(event.currentTarget).toBe(PARENT);
239 }
240 );
192 - EventPluginHub.putListener(
193 - getInternal(GRANDPARENT),
241 + putListener(
242 + GRANDPARENT,
243 ON_CLICK_KEY,
244 function(event) {
196 - recordID(getInternal(GRANDPARENT));
245 + recordID(GRANDPARENT);
246 expect(event.currentTarget).toBe(GRANDPARENT);
247 }
248 );
249 ReactTestUtils.Simulate.click(CHILD);
250 expect(idCallOrder.length).toBe(3);
202 - expect(idCallOrder[0]).toBe(getInternal(CHILD));
203 - expect(idCallOrder[1]).toBe(getInternal(PARENT));
204 - expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT));
251 + expect(idCallOrder[0]).toBe(CHILD);
252 + expect(idCallOrder[1]).toBe(PARENT);
253 + expect(idCallOrder[2]).toBe(GRANDPARENT);
254 });
255
256 it('should support stopPropagation()', () => {
208 - EventPluginHub.putListener(
209 - getInternal(CHILD),
257 + putListener(
258 + CHILD,
259 ON_CLICK_KEY,
211 - recordID.bind(null, getInternal(CHILD))
260 + recordID.bind(null, CHILD)
261 );
213 - EventPluginHub.putListener(
214 - getInternal(PARENT),
262 + putListener(
263 + PARENT,
264 ON_CLICK_KEY,
216 - recordIDAndStopPropagation.bind(null, getInternal(PARENT))
265 + recordIDAndStopPropagation.bind(null, PARENT)
266 );
218 - EventPluginHub.putListener(
219 - getInternal(GRANDPARENT),
267 + putListener(
268 + GRANDPARENT,
269 ON_CLICK_KEY,
221 - recordID.bind(null, getInternal(GRANDPARENT))
270 + recordID.bind(null, GRANDPARENT)
271 );
272 ReactTestUtils.Simulate.click(CHILD);
273 expect(idCallOrder.length).toBe(2);
225 - expect(idCallOrder[0]).toBe(getInternal(CHILD));
226 - expect(idCallOrder[1]).toBe(getInternal(PARENT));
274 + expect(idCallOrder[0]).toBe(CHILD);
275 + expect(idCallOrder[1]).toBe(PARENT);
276 });
277
278 it('should stop after first dispatch if stopPropagation', () => {
230 - EventPluginHub.putListener(
231 - getInternal(CHILD),
279 + putListener(
280 + CHILD,
281 ON_CLICK_KEY,
233 - recordIDAndStopPropagation.bind(null, getInternal(CHILD))
282 + recordIDAndStopPropagation.bind(null, CHILD)
283 );
235 - EventPluginHub.putListener(
236 - getInternal(PARENT),
284 + putListener(
285 + PARENT,
286 ON_CLICK_KEY,
238 - recordID.bind(null, getInternal(PARENT))
287 + recordID.bind(null, PARENT)
288 );
240 - EventPluginHub.putListener(
241 - getInternal(GRANDPARENT),
289 + putListener(
290 + GRANDPARENT,
291 ON_CLICK_KEY,
243 - recordID.bind(null, getInternal(GRANDPARENT))
292 + recordID.bind(null, GRANDPARENT)
293 );
294 ReactTestUtils.Simulate.click(CHILD);
295 expect(idCallOrder.length).toBe(1);
247 - expect(idCallOrder[0]).toBe(getInternal(CHILD));
296 + expect(idCallOrder[0]).toBe(CHILD);
297 });
298
299 it('should not stopPropagation if false is returned', () => {
251 - EventPluginHub.putListener(
252 - getInternal(CHILD),
300 + putListener(
301 + CHILD,
302 ON_CLICK_KEY,
254 - recordIDAndReturnFalse.bind(null, getInternal(CHILD))
303 + recordIDAndReturnFalse.bind(null, CHILD)
304 );
256 - EventPluginHub.putListener(
257 - getInternal(PARENT),
305 + putListener(
306 + PARENT,
307 ON_CLICK_KEY,
259 - recordID.bind(null, getInternal(PARENT))
308 + recordID.bind(null, PARENT)
309 );
261 - EventPluginHub.putListener(
262 - getInternal(GRANDPARENT),
310 + putListener(
311 + GRANDPARENT,
312 ON_CLICK_KEY,
264 - recordID.bind(null, getInternal(GRANDPARENT))
313 + recordID.bind(null, GRANDPARENT)
314 );
315 spyOn(console, 'error');
316 ReactTestUtils.Simulate.click(CHILD);
317 expect(idCallOrder.length).toBe(3);
269 - expect(idCallOrder[0]).toBe(getInternal(CHILD));
270 - expect(idCallOrder[1]).toBe(getInternal(PARENT));
271 - expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT));
318 + expect(idCallOrder[0]).toBe(CHILD);
319 + expect(idCallOrder[1]).toBe(PARENT);
320 + expect(idCallOrder[2]).toBe(GRANDPARENT);
321 expectDev(console.error.calls.count()).toEqual(0);
322 });
323
@@ -284,15 +333,15 @@ describe('ReactBrowserEventEmitter', () => {
333 it('should invoke handlers that were removed while bubbling', () => {
334 var handleParentClick = jest.fn();
335 var handleChildClick = function(event) {
287 - EventPluginHub.deleteAllListeners(getInternal(PARENT));
336 + deleteAllListeners(PARENT);
337 };
289 - EventPluginHub.putListener(
290 - getInternal(CHILD),
338 + putListener(
339 + CHILD,
340 ON_CLICK_KEY,
341 handleChildClick
342 );
294 - EventPluginHub.putListener(
295 - getInternal(PARENT),
343 + putListener(
344 + PARENT,
345 ON_CLICK_KEY,
346 handleParentClick
347 );
@@ -303,14 +352,14 @@ describe('ReactBrowserEventEmitter', () => {
352 it('should not invoke newly inserted handlers while bubbling', () => {
353 var handleParentClick = jest.fn();
354 var handleChildClick = function(event) {
306 - EventPluginHub.putListener(
307 - getInternal(PARENT),
355 + putListener(
356 + PARENT,
357 ON_CLICK_KEY,
358 handleParentClick
359 );
360 };
312 - EventPluginHub.putListener(
313 - getInternal(CHILD),
361 + putListener(
362 + CHILD,
363 ON_CLICK_KEY,
364 handleChildClick
365 );
@@ -319,21 +368,21 @@ describe('ReactBrowserEventEmitter', () => {
368 });
369
370 it('should have mouse enter simulated by test utils', () => {
322 - EventPluginHub.putListener(
323 - getInternal(CHILD),
371 + putListener(
372 + CHILD,
373 ON_MOUSE_ENTER_KEY,
325 - recordID.bind(null, getInternal(CHILD))
374 + recordID.bind(null, CHILD)
375 );
376 ReactTestUtils.Simulate.mouseEnter(CHILD);
377 expect(idCallOrder.length).toBe(1);
329 - expect(idCallOrder[0]).toBe(getInternal(CHILD));
378 + expect(idCallOrder[0]).toBe(CHILD);
379 });
380
381 it('should infer onTouchTap from a touchStart/End', () => {
333 - EventPluginHub.putListener(
334 - getInternal(CHILD),
382 + putListener(
383 + CHILD,
384 ON_TOUCH_TAP_KEY,
336 - recordID.bind(null, getInternal(CHILD))
385 + recordID.bind(null, CHILD)
386 );
387 ReactTestUtils.SimulateNative.touchStart(
388 CHILD,
@@ -344,14 +393,14 @@ describe('ReactBrowserEventEmitter', () => {
393 ReactTestUtils.nativeTouchData(0, 0)
394 );
395 expect(idCallOrder.length).toBe(1);
347 - expect(idCallOrder[0]).toBe(getInternal(CHILD));
396 + expect(idCallOrder[0]).toBe(CHILD);
397 });
398
399 it('should infer onTouchTap from when dragging below threshold', () => {
351 - EventPluginHub.putListener(
352 - getInternal(CHILD),
400 + putListener(
401 + CHILD,
402 ON_TOUCH_TAP_KEY,
354 - recordID.bind(null, getInternal(CHILD))
403 + recordID.bind(null, CHILD)
404 );
405 ReactTestUtils.SimulateNative.touchStart(
406 CHILD,
@@ -362,14 +411,14 @@ describe('ReactBrowserEventEmitter', () => {
411 ReactTestUtils.nativeTouchData(0, tapMoveThreshold - 1)
412 );
413 expect(idCallOrder.length).toBe(1);
365 - expect(idCallOrder[0]).toBe(getInternal(CHILD));
414 + expect(idCallOrder[0]).toBe(CHILD);
415 });
416
417 it('should not onTouchTap from when dragging beyond threshold', () => {
369 - EventPluginHub.putListener(
370 - getInternal(CHILD),
418 + putListener(
419 + CHILD,
420 ON_TOUCH_TAP_KEY,
372 - recordID.bind(null, getInternal(CHILD))
421 + recordID.bind(null, CHILD)
422 );
423 ReactTestUtils.SimulateNative.touchStart(
424 CHILD,
@@ -423,20 +472,20 @@ describe('ReactBrowserEventEmitter', () => {
472 });
473
474 it('should bubble onTouchTap', () => {
426 - EventPluginHub.putListener(
427 - getInternal(CHILD),
475 + putListener(
476 + CHILD,
477 ON_TOUCH_TAP_KEY,
429 - recordID.bind(null, getInternal(CHILD))
478 + recordID.bind(null, CHILD)
479 );
431 - EventPluginHub.putListener(
432 - getInternal(PARENT),
480 + putListener(
481 + PARENT,
482 ON_TOUCH_TAP_KEY,
434 - recordID.bind(null, getInternal(PARENT))
483 + recordID.bind(null, PARENT)
484 );
436 - EventPluginHub.putListener(
437 - getInternal(GRANDPARENT),
485 + putListener(
486 + GRANDPARENT,
487 ON_TOUCH_TAP_KEY,
439 - recordID.bind(null, getInternal(GRANDPARENT))
488 + recordID.bind(null, GRANDPARENT)
489 );
490 ReactTestUtils.SimulateNative.touchStart(
491 CHILD,
@@ -447,9 +496,9 @@ describe('ReactBrowserEventEmitter', () => {
496 ReactTestUtils.nativeTouchData(0, 0)
497 );
498 expect(idCallOrder.length).toBe(3);
450 - expect(idCallOrder[0]).toBe(getInternal(CHILD));
451 - expect(idCallOrder[1]).toBe(getInternal(PARENT));
452 - expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT));
499 + expect(idCallOrder[0]).toBe(CHILD);
500 + expect(idCallOrder[1]).toBe(PARENT);
501 + expect(idCallOrder[2]).toBe(GRANDPARENT);
502 });
503
504 it('should not crash ensureScrollValueMonitoring when createEvent returns null', () => {
src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
-80
@@ -972,61 +972,6 @@ describe('ReactDOMComponent', () => {
972 expect(tracker.getValue()).toEqual('foo');
973 });
974
975 - it('should execute custom event plugin listening behavior', () => {
976 - var SimpleEventPlugin = require('SimpleEventPlugin');
977 -
978 - SimpleEventPlugin.didPutListener = jest.fn();
979 - SimpleEventPlugin.willDeleteListener = jest.fn();
980 -
981 - var container = document.createElement('div');
982 - ReactDOM.render(
983 - <div onClick={() => true} />,
984 - container
985 - );
986 -
987 - expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(1);
988 -
989 - ReactDOM.unmountComponentAtNode(container);
990 -
991 - expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(1);
992 - });
993 -
994 - it('should handle null and missing properly with event hooks', () => {
995 - var SimpleEventPlugin = require('SimpleEventPlugin');
996 -
997 - SimpleEventPlugin.didPutListener = jest.fn();
998 - SimpleEventPlugin.willDeleteListener = jest.fn();
999 - var container = document.createElement('div');
1000 -
1001 - ReactDOM.render(<div onClick={false} />, container);
1002 - expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(0);
1003 - expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(0);
1004 -
1005 - ReactDOM.render(<div onClick={null} />, container);
1006 - expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(0);
1007 - expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(0);
1008 -
1009 - ReactDOM.render(<div onClick={() => 'apple'} />, container);
1010 - expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(1);
1011 - expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(0);
1012 -
1013 - ReactDOM.render(<div onClick={() => 'banana'} />, container);
1014 - expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(2);
1015 - expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(0);
1016 -
1017 - ReactDOM.render(<div onClick={null} />, container);
1018 - expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(2);
1019 - expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(1);
1020 -
1021 - ReactDOM.render(<div />, container);
1022 - expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(2);
1023 - expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(1);
1024 -
1025 - ReactDOM.unmountComponentAtNode(container);
1026 - expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(2);
1027 - expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(1);
1028 - });
1029 -
975 it('should warn for children on void elements', () => {
976 class X extends React.Component {
977 render() {
@@ -1157,31 +1102,6 @@ describe('ReactDOMComponent', () => {
1102 });
1103
1104 describe('unmountComponent', () => {
1160 - it('should clean up listeners', () => {
1161 - var EventPluginHub = require('EventPluginHub');
1162 - var ReactDOMComponentTree = require('ReactDOMComponentTree');
1163 -
1164 - var container = document.createElement('div');
1165 - document.body.appendChild(container);
1166 -
1167 - var callback = function() {};
1168 - var instance = <div onClick={callback} />;
1169 - instance = ReactDOM.render(instance, container);
1170 -
1171 - var rootNode = ReactDOM.findDOMNode(instance);
1172 - var inst = ReactDOMComponentTree.getInstanceFromNode(rootNode);
1173 - expect(
1174 - EventPluginHub.getListener(inst, 'onClick')
1175 - ).toBe(callback);
1176 - expect(rootNode).toBe(ReactDOM.findDOMNode(instance));
1177 -
1178 - ReactDOM.unmountComponentAtNode(container);
1179 -
1180 - expect(
1181 - EventPluginHub.getListener(inst, 'onClick')
1182 - ).toBe(undefined);
1183 - });
1184 -
1105 it('should clean up input value tracking', () => {
1106 var container = document.createElement('div');
1107 var node = ReactDOM.render(<input type="text" defaultValue="foo"/>, container);
src/renderers/dom/stack/client/ReactDOMComponent.js
+3 -46
@@ -19,7 +19,6 @@ var DOMLazyTree = require('DOMLazyTree');
19 var DOMNamespaces = require('DOMNamespaces');
20 var DOMProperty = require('DOMProperty');
21 var DOMPropertyOperations = require('DOMPropertyOperations');
22 -var EventPluginHub = require('EventPluginHub');
22 var EventPluginRegistry = require('EventPluginRegistry');
23 var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
24 var ReactDOMComponentFlags = require('ReactDOMComponentFlags');
@@ -43,7 +42,6 @@ var warning = require('warning');
42 var didWarnShadyDOM = false;
43
44 var Flags = ReactDOMComponentFlags;
46 -var deleteListener = EventPluginHub.deleteListener;
45 var getNode = ReactDOMComponentTree.getNodeFromInstance;
46 var listenTo = ReactBrowserEventEmitter.listenTo;
47 var registrationNameModules = EventPluginRegistry.registrationNameModules;
@@ -205,30 +203,6 @@ function assertValidProps(component, props) {
203 );
204 }
205
208 -function enqueuePutListener(inst, registrationName, listener, transaction) {
209 - if (transaction instanceof ReactServerRenderingTransaction) {
210 - return;
211 - }
212 - if (__DEV__) {
213 - // IE8 has no API for event capturing and the `onScroll` event doesn't
214 - // bubble.
215 - warning(
216 - registrationName !== 'onScroll' || isEventSupported('scroll', true),
217 - 'This browser doesn\'t support the `onScroll` event'
218 - );
219 - }
220 - var containerInfo = inst._hostContainerInfo;
221 - var isDocumentFragment = containerInfo._node && containerInfo._node.nodeType === DOC_FRAGMENT_TYPE;
222 - var doc = isDocumentFragment ? containerInfo._node : containerInfo._ownerDocument;
223 - listenTo(registrationName, doc);
224 - transaction.getReactMountReady().enqueue(putListener, {
225 - inst: inst,
226 - registrationName: registrationName,
227 - listener: listener,
228 - });
229 -}
230 -
231 -// TODO: This is coming from future #8192. Dedupe this and enqueuePutListener.
206 function ensureListeningTo(inst, registrationName, transaction) {
207 if (transaction instanceof ReactServerRenderingTransaction) {
208 return;
@@ -247,15 +221,6 @@ function ensureListeningTo(inst, registrationName, transaction) {
221 listenTo(registrationName, doc);
222 }
223
250 -function putListener() {
251 - var listenerToPut = this;
252 - EventPluginHub.putListener(
253 - listenerToPut.inst,
254 - listenerToPut.registrationName,
255 - listenerToPut.listener
256 - );
257 -}
258 -
224 function inputPostMount() {
225 var inst = this;
226 ReactDOMInput.postMountWrapper(inst);
@@ -792,7 +757,7 @@ ReactDOMComponent.Mixin = {
757 }
758 if (registrationNameModules.hasOwnProperty(propKey)) {
759 if (propValue) {
795 - enqueuePutListener(this, propKey, propValue, transaction);
760 + ensureListeningTo(this, propKey, transaction);
761 }
762 } else {
763 if (propKey === STYLE) {
@@ -1047,12 +1012,7 @@ ReactDOMComponent.Mixin = {
1012 }
1013 this._previousStyleCopy = null;
1014 } else if (registrationNameModules.hasOwnProperty(propKey)) {
1050 - if (lastProps[propKey]) {
1051 - // Only call deleteListener if there was a listener previously or
1052 - // else willDeleteListener gets called when there wasn't actually a
1053 - // listener (e.g., onClick={null})
1054 - deleteListener(this, propKey);
1055 - }
1015 + // Do nothing for event names.
1016 } else if (isCustomComponent(this._tag, lastProps)) {
1017 if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
1018 DOMPropertyOperations.deleteValueForAttribute(
@@ -1113,9 +1073,7 @@ ReactDOMComponent.Mixin = {
1073 }
1074 } else if (registrationNameModules.hasOwnProperty(propKey)) {
1075 if (nextProp) {
1116 - enqueuePutListener(this, propKey, nextProp, transaction);
1117 - } else if (lastProp) {
1118 - deleteListener(this, propKey);
1076 + ensureListeningTo(this, propKey, transaction);
1077 }
1078 } else if (isCustomComponentTag) {
1079 if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
@@ -1264,7 +1222,6 @@ ReactDOMComponent.Mixin = {
1222
1223 this.unmountChildren(safely, skipLifecycle);
1224 ReactDOMComponentTree.uncacheNode(this);
1267 - EventPluginHub.deleteAllListeners(this);
1225 this._rootNodeID = 0;
1226 this._domID = 0;
1227 this._wrapperState = null;
src/renderers/dom/stack/server/__tests__/ReactServerRendering-test.js
+1 -19
@@ -85,15 +85,7 @@ describe('ReactServerRendering', () => {
85 expect(response).toBe('<!-- react-empty: 1 -->');
86 });
87
88 - it('should not register event listeners', () => {
89 - var EventPluginHub = require('EventPluginHub');
90 - var cb = jest.fn();
91 -
92 - ReactServerRendering.renderToString(
93 - <span onClick={cb}>hello world</span>
94 - );
95 - expect(EventPluginHub.__getListenerBank()).toEqual({});
96 - });
88 + // TODO: Test that listeners are not registered onto any document/container.
89
90 it('should render composite components', () => {
91 class Parent extends React.Component {
@@ -322,16 +314,6 @@ describe('ReactServerRendering', () => {
314 expect(response).toBe('<span>hello world</span>');
315 });
316
325 - it('should not register event listeners', () => {
326 - var EventPluginHub = require('EventPluginHub');
327 - var cb = jest.fn();
328 -
329 - ReactServerRendering.renderToStaticMarkup(
330 - <span onClick={cb}>hello world</span>
331 - );
332 - expect(EventPluginHub.__getListenerBank()).toEqual({});
333 - });
334 -
317 it('should only execute certain lifecycle methods', () => {
318 function runTest() {
319 var lifecycle = [];
src/renderers/native/ReactNativeBaseComponent.js
-43
@@ -14,18 +14,12 @@
14 var NativeMethodsMixin = require('NativeMethodsMixin');
15 var ReactNativeAttributePayload = require('ReactNativeAttributePayload');
16 var ReactNativeComponentTree = require('ReactNativeComponentTree');
17 -var ReactNativeEventEmitter = require('ReactNativeEventEmitter');
17 var ReactNativeTagHandles = require('ReactNativeTagHandles');
18 var ReactMultiChild = require('ReactMultiChild');
19 var UIManager = require('UIManager');
20
21 var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
22
24 -var registrationNames = ReactNativeEventEmitter.registrationNames;
25 -var putListener = ReactNativeEventEmitter.putListener;
26 -var deleteListener = ReactNativeEventEmitter.deleteListener;
27 -var deleteAllListeners = ReactNativeEventEmitter.deleteAllListeners;
28 -
23 type ReactNativeBaseComponentViewConfig = {
24 validAttributes: Object;
25 uiViewClassName: string;
@@ -57,7 +51,6 @@ ReactNativeBaseComponent.Mixin = {
51
52 unmountComponent: function(safely, skipLifecycle) {
53 ReactNativeComponentTree.uncacheNode(this);
60 - deleteAllListeners(this);
54 this.unmountChildren(safely, skipLifecycle);
55 this._rootNodeID = 0;
56 },
@@ -123,44 +116,9 @@ ReactNativeBaseComponent.Mixin = {
116 );
117 }
118
126 - this._reconcileListenersUponUpdate(
127 - prevElement.props,
128 - nextElement.props
129 - );
119 this.updateChildren(nextElement.props.children, transaction, context);
120 },
121
133 - /**
134 - * @param {object} initialProps Native component props.
135 - */
136 - _registerListenersUponCreation: function(initialProps) {
137 - for (var key in initialProps) {
138 - // NOTE: The check for `!props[key]`, is only possible because this method
139 - // registers listeners the *first* time a component is created.
140 - if (registrationNames[key] && initialProps[key]) {
141 - var listener = initialProps[key];
142 - putListener(this, key, listener);
143 - }
144 - }
145 - },
146 -
147 - /**
148 - * Reconciles event listeners, adding or removing if necessary.
149 - * @param {object} prevProps Native component props including events.
150 - * @param {object} nextProps Next native component props including events.
151 - */
152 - _reconcileListenersUponUpdate: function(prevProps, nextProps) {
153 - for (var key in nextProps) {
154 - if (registrationNames[key] && (nextProps[key] !== prevProps[key])) {
155 - if (nextProps[key]) {
156 - putListener(this, key, nextProps[key]);
157 - } else {
158 - deleteListener(this, key);
159 - }
160 - }
161 - }
162 - },
163 -
122 /**
123 * Currently this still uses IDs for reconciliation so this can return null.
124 *
@@ -207,7 +165,6 @@ ReactNativeBaseComponent.Mixin = {
165
166 ReactNativeComponentTree.precacheNode(this, tag);
167
210 - this._registerListenersUponCreation(this._currentElement.props);
168 this.initializeChildren(
169 this._currentElement.props.children,
170 tag,
src/renderers/native/ReactNativeEventEmitter.js
-15
@@ -78,29 +78,14 @@ var removeTouchesAtIndices = function(
78 return rippedOut;
79 };
80
81 -/**
82 - * `ReactNativeEventEmitter` is used to attach top-level event listeners. For example:
83 - *
84 - * ReactNativeEventEmitter.putListener('myID', 'onClick', myFunction);
85 - *
86 - * This would allocate a "registration" of `('onClick', myFunction)` on 'myID'.
87 - *
88 - * @internal
89 - */
81 var ReactNativeEventEmitter = {
82
83 ...ReactEventEmitterMixin,
84
85 registrationNames: EventPluginRegistry.registrationNameModules,
86
96 - putListener: EventPluginHub.putListener,
97 -
87 getListener: EventPluginHub.getListener,
88
100 - deleteListener: EventPluginHub.deleteListener,
101 -
102 - deleteAllListeners: EventPluginHub.deleteAllListeners,
103 -
89 /**
90 * Internal version of `receiveEvent` in terms of normalized (non-tag)
91 * `rootNodeID`.
src/renderers/shared/shared/event/EventPluginHub.js
+7 -97
@@ -19,11 +19,6 @@ var accumulateInto = require('accumulateInto');
19 var forEachAccumulated = require('forEachAccumulated');
20 var invariant = require('invariant');
21
22 -/**
23 - * Internal store for event listeners
24 - */
25 -var listenerBank = {};
26 -
22 /**
23 * Internal queue of events that have accumulated their dispatches and are
24 * waiting to have their dispatches executed.
@@ -53,12 +48,6 @@ var executeDispatchesAndReleaseTopLevel = function(e) {
48 return executeDispatchesAndRelease(e, false);
49 };
50
56 -var getDictionaryKey = function(inst) {
57 - // Prevents V8 performance issue:
58 - // https://github.com/facebook/react/pull/7232
59 - return '.' + inst._rootNodeID;
60 -};
61 -
51 /**
52 * This is a unified interface for event plugins to be installed and configured.
53 *
@@ -102,87 +91,19 @@ var EventPluginHub = {
91 },
92
93 /**
105 - * Stores `listener` at `listenerBank[registrationName][key]`. Is idempotent.
106 - *
94 * @param {object} inst The instance, which is the source of events.
95 * @param {string} registrationName Name of listener (e.g. `onClick`).
109 - * @param {function} listener The callback to store.
96 + * @return {?function} The stored callback.
97 */
111 - putListener: function(inst, registrationName, listener) {
98 + getListener: function(inst, registrationName) {
99 + var listener = inst._currentElement.props[registrationName];
100 invariant(
113 - typeof listener === 'function',
101 + !listener || typeof listener === 'function',
102 'Expected %s listener to be a function, instead got type %s',
115 - registrationName, typeof listener
103 + registrationName,
104 + typeof listener
105 );
117 -
118 - var key = getDictionaryKey(inst);
119 - var bankForRegistrationName =
120 - listenerBank[registrationName] || (listenerBank[registrationName] = {});
121 - bankForRegistrationName[key] = listener;
122 -
123 - var PluginModule =
124 - EventPluginRegistry.registrationNameModules[registrationName];
125 - if (PluginModule && PluginModule.didPutListener) {
126 - PluginModule.didPutListener(inst, registrationName, listener);
127 - }
128 - },
129 -
130 - /**
131 - * @param {object} inst The instance, which is the source of events.
132 - * @param {string} registrationName Name of listener (e.g. `onClick`).
133 - * @return {?function} The stored callback.
134 - */
135 - getListener: function(inst, registrationName) {
136 - var bankForRegistrationName = listenerBank[registrationName];
137 - var key = getDictionaryKey(inst);
138 - return bankForRegistrationName && bankForRegistrationName[key];
139 - },
140 -
141 - /**
142 - * Deletes a listener from the registration bank.
143 - *
144 - * @param {object} inst The instance, which is the source of events.
145 - * @param {string} registrationName Name of listener (e.g. `onClick`).
146 - */
147 - deleteListener: function(inst, registrationName) {
148 - var PluginModule =
149 - EventPluginRegistry.registrationNameModules[registrationName];
150 - if (PluginModule && PluginModule.willDeleteListener) {
151 - PluginModule.willDeleteListener(inst, registrationName);
152 - }
153 -
154 - var bankForRegistrationName = listenerBank[registrationName];
155 - // TODO: This should never be null -- when is it?
156 - if (bankForRegistrationName) {
157 - var key = getDictionaryKey(inst);
158 - delete bankForRegistrationName[key];
159 - }
160 - },
161 -
162 - /**
163 - * Deletes all listeners for the DOM element with the supplied ID.
164 - *
165 - * @param {object} inst The instance, which is the source of events.
166 - */
167 - deleteAllListeners: function(inst) {
168 - var key = getDictionaryKey(inst);
169 - for (var registrationName in listenerBank) {
170 - if (!listenerBank.hasOwnProperty(registrationName)) {
171 - continue;
172 - }
173 -
174 - if (!listenerBank[registrationName][key]) {
175 - continue;
176 - }
177 -
178 - var PluginModule =
179 - EventPluginRegistry.registrationNameModules[registrationName];
180 - if (PluginModule && PluginModule.willDeleteListener) {
181 - PluginModule.willDeleteListener(inst, registrationName);
182 - }
183 -
184 - delete listenerBank[registrationName][key];
185 - }
106 + return listener;
107 },
108
109 /**
@@ -260,17 +181,6 @@ var EventPluginHub = {
181 ReactErrorUtils.rethrowCaughtError();
182 },
183
263 - /**
264 - * These are needed for tests only. Do not use!
265 - */
266 - __purge: function() {
267 - listenerBank = {};
268 - },
269 -
270 - __getListenerBank: function() {
271 - return listenerBank;
272 - },
273 -
184 };
185
186 module.exports = EventPluginHub;
src/renderers/shared/shared/event/EventPluginRegistry.js
+1 -2
@@ -130,8 +130,7 @@ function publishEventForPlugin(
130 }
131
132 /**
133 - * Publishes a registration name that is used to identify dispatched events and
134 - * can be used with `EventPluginHub.putListener` to register listeners.
133 + * Publishes a registration name that is used to identify dispatched events.
134 *
135 * @param {string} registrationName Registration name to add.
136 * @param {object} PluginModule Plugin publishing the event.
src/renderers/shared/shared/event/PluginModuleType.js
-9
@@ -36,14 +36,5 @@ export type PluginModule<NativeEvent> = {
36 nativeTarget: NativeEvent,
37 nativeEventTarget: EventTarget,
38 ) => null | ReactSyntheticEvent,
39 - didPutListener?: (
40 - inst: ReactInstance,
41 - registrationName: string,
42 - listener: () => void,
43 - ) => void,
44 - willDeleteListener?: (
45 - inst: ReactInstance,
46 - registrationName: string,
47 - ) => void,
39 tapMoveThreshold?: number,
40 };
src/renderers/shared/shared/event/__tests__/EventPluginHub-test.js
+19 -7
@@ -14,21 +14,33 @@
14 jest.mock('isEventSupported');
15
16 describe('EventPluginHub', () => {
17 - var EventPluginHub;
18 - var isEventSupported;
17 + var React;
18 + var ReactTestUtils;
19
20 beforeEach(() => {
21 jest.resetModuleRegistry();
22 - EventPluginHub = require('EventPluginHub');
23 - isEventSupported = require('isEventSupported');
24 - isEventSupported.mockReturnValueOnce(false);
22 + React = require('React');
23 + ReactTestUtils = require('ReactTestUtils');
24 });
25
27 - it('should prevent non-function listeners', () => {
26 + it('should prevent non-function listeners, at dispatch', () => {
27 + var node = ReactTestUtils.renderIntoDocument(
28 + <div onClick="not a function" />
29 + );
30 expect(function() {
29 - EventPluginHub.putListener(1, 'onClick', 'not a function');
31 + ReactTestUtils.SimulateNative.click(node);
32 }).toThrowError(
33 'Expected onClick listener to be a function, instead got type string'
34 );
35 });
36 +
37 + it('should not prevent null listeners, at dispatch', () => {
38 + var node = ReactTestUtils.renderIntoDocument(
39 + <div onClick={null} />
40 + );
41 + expect(function() {
42 + ReactTestUtils.SimulateNative.click(node);
43 + }).not.toThrow();
44 + });
45 +
46 });
src/renderers/shared/shared/event/eventPlugins/__tests__/ResponderEventPlugin-test.js
+38 -8
@@ -233,7 +233,7 @@ var registerTestHandlers = function(eventTestConfig, readableIDToID) {
233 }
234 return config.returnVal;
235 }.bind(null, readableID, nodeConfig);
236 - EventPluginHub.putListener(getInstanceFromNode(id), registrationName, handler);
236 + putListener(getInstanceFromNode(id), registrationName, handler);
237 }
238 };
239 for (var eventName in eventTestConfig) {
@@ -258,9 +258,6 @@ var registerTestHandlers = function(eventTestConfig, readableIDToID) {
258 return runs;
259 };
260
261 -
262 -
263 -
261 var run = function(config, hierarchyConfig, nativeEventConfig) {
262 var max = NA;
263 var searchForMax = function(nodeConfig) {
@@ -309,10 +306,30 @@ var PARENT_HOST_NODE = { };
306 var CHILD_HOST_NODE = { };
307 var CHILD_HOST_NODE2 = { };
308
312 -var GRANDPARENT_INST = { _hostParent: null, _rootNodeID: '1', _hostNode: GRANDPARENT_HOST_NODE };
313 -var PARENT_INST = { _hostParent: GRANDPARENT_INST, _rootNodeID: '2', _hostNode: PARENT_HOST_NODE };
314 -var CHILD_INST = { _hostParent: PARENT_INST, _rootNodeID: '3', _hostNode: CHILD_HOST_NODE };
315 -var CHILD_INST2 = { _hostParent: PARENT_INST, _rootNodeID: '4', _hostNode: CHILD_HOST_NODE2 };
309 +var GRANDPARENT_INST = {
310 + _hostParent: null,
311 + _rootNodeID: '1',
312 + _hostNode: GRANDPARENT_HOST_NODE,
313 + _currentElement: { props: {} },
314 +};
315 +var PARENT_INST = {
316 + _hostParent: GRANDPARENT_INST,
317 + _rootNodeID: '2',
318 + _hostNode: PARENT_HOST_NODE,
319 + _currentElement: { props: {} },
320 +};
321 +var CHILD_INST = {
322 + _hostParent: PARENT_INST,
323 + _rootNodeID: '3',
324 + _hostNode: CHILD_HOST_NODE,
325 + _currentElement: { props: {} },
326 +};
327 +var CHILD_INST2 = {
328 + _hostParent: PARENT_INST,
329 + _rootNodeID: '4',
330 + _hostNode: CHILD_HOST_NODE2,
331 + _currentElement: { props: {} },
332 +};
333
334 GRANDPARENT_HOST_NODE._reactInstance = GRANDPARENT_INST;
335 PARENT_HOST_NODE._reactInstance = PARENT_INST;
@@ -339,6 +356,14 @@ function getNodeFromInstance(inst) {
356 return inst._hostNode;
357 }
358
359 +function putListener(node, registrationName, handler) {
360 + node._currentElement.props[registrationName] = handler;
361 +}
362 +
363 +function deleteAllListeners(node) {
364 + node._currentElement.props = {};
365 +}
366 +
367 describe('ResponderEventPlugin', () => {
368
369 beforeEach(() => {
@@ -348,6 +373,11 @@ describe('ResponderEventPlugin', () => {
373 EventPluginUtils = require('EventPluginUtils');
374 ResponderEventPlugin = require('ResponderEventPlugin');
375
376 + deleteAllListeners(GRANDPARENT_INST);
377 + deleteAllListeners(PARENT_INST);
378 + deleteAllListeners(CHILD_INST);
379 + deleteAllListeners(CHILD_INST2);
380 +
381 EventPluginUtils.injection.injectComponentTree({
382 getInstanceFromNode,
383 getNodeFromInstance,
src/renderers/shared/stack/reconciler/__tests__/ReactErrorBoundaries-test.js
-20
@@ -879,26 +879,6 @@ describe('ReactErrorBoundaries', () => {
879 ]);
880 });
881
882 - it('does not register event handlers for unmounted children', () => {
883 - var EventPluginHub = require('EventPluginHub');
884 - var container = document.createElement('div');
885 - EventPluginHub.putListener = jest.fn();
886 - ReactDOM.render(
887 - <ErrorBoundary>
888 - <button onClick={() => {}}>Click me</button>
889 - <BrokenRender />
890 - </ErrorBoundary>,
891 - container
892 - );
893 - expect(EventPluginHub.putListener).not.toBeCalled();
894 -
895 - log.length = 0;
896 - ReactDOM.unmountComponentAtNode(container);
897 - expect(log).toEqual([
898 - 'ErrorBoundary componentWillUnmount',
899 - ]);
900 - });
901 -
882 it('does not call componentWillUnmount when aborting initial mount', () => {
883 var container = document.createElement('div');
884 ReactDOM.render(