From 90cd545b379b120779e7b743271d00f9da431f98 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 1 Sep 2017 11:01:05 -0700 Subject: [PATCH 1/4] Remove EventListener dependency from test --- .../ReactBrowserEventEmitter-test.js | 31 +++++-------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/src/renderers/dom/shared/__tests__/ReactBrowserEventEmitter-test.js b/src/renderers/dom/shared/__tests__/ReactBrowserEventEmitter-test.js index 6239a6ac112..ca6784df033 100644 --- a/src/renderers/dom/shared/__tests__/ReactBrowserEventEmitter-test.js +++ b/src/renderers/dom/shared/__tests__/ReactBrowserEventEmitter-test.js @@ -11,7 +11,6 @@ 'use strict'; -var EventListener; var EventPluginHub; var EventPluginRegistry; var React; @@ -59,7 +58,6 @@ describe('ReactBrowserEventEmitter', () => { beforeEach(() => { jest.resetModules(); LISTENER.mockClear(); - EventListener = require('fbjs/lib/EventListener'); // TODO: can we express this test with only public API? EventPluginHub = require('EventPluginHub'); EventPluginRegistry = require('EventPluginRegistry'); @@ -376,43 +374,30 @@ describe('ReactBrowserEventEmitter', () => { }); it('should listen to events only once', () => { - spyOn(EventListener, 'listen'); + spyOn(document, 'addEventListener'); ReactBrowserEventEmitter.listenTo(ON_CLICK_KEY, document); ReactBrowserEventEmitter.listenTo(ON_CLICK_KEY, document); - expect(EventListener.listen.calls.count()).toBe(1); + expect(document.addEventListener.calls.count()).toBe(1); }); it('should work with event plugins without dependencies', () => { - spyOn(EventListener, 'listen'); + spyOn(document, 'addEventListener'); ReactBrowserEventEmitter.listenTo(ON_CLICK_KEY, document); - expect(EventListener.listen.calls.argsFor(0)[1]).toBe('click'); + expect(document.addEventListener.calls.argsFor(0)[0]).toBe('click'); }); it('should work with event plugins with dependencies', () => { - spyOn(EventListener, 'listen'); - spyOn(EventListener, 'capture'); + spyOn(document, 'addEventListener'); ReactBrowserEventEmitter.listenTo(ON_CHANGE_KEY, document); - var setEventListeners = []; - var listenCalls = EventListener.listen.calls.allArgs(); - var captureCalls = EventListener.capture.calls.allArgs(); - for (var i = 0; i < listenCalls.length; i++) { - setEventListeners.push(listenCalls[i][1]); - } - for (i = 0; i < captureCalls.length; i++) { - setEventListeners.push(captureCalls[i][1]); - } - var module = EventPluginRegistry.registrationNameModules[ON_CHANGE_KEY]; var dependencies = module.eventTypes.change.dependencies; - expect(setEventListeners.length).toEqual(dependencies.length); - - for (i = 0; i < setEventListeners.length; i++) { - expect(dependencies.indexOf(setEventListeners[i])).toBeTruthy(); - } + expect(document.addEventListener.calls.count()).toEqual( + dependencies.length, + ); }); it('should bubble onTouchTap', () => { From 4592f72d0c32954e6289c56647c927a436d1e4e1 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 1 Sep 2017 11:04:55 -0700 Subject: [PATCH 2/4] Remove EventListener from the build Inline the part that we actually use. Drop IE8 polyfill and unsubscription code. --- .../dom/shared/ReactBrowserEventEmitter.js | 4 ++-- src/renderers/dom/shared/ReactDOMEventListener.js | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/renderers/dom/shared/ReactBrowserEventEmitter.js b/src/renderers/dom/shared/ReactBrowserEventEmitter.js index 1c2661b57f9..2a55c0e06a5 100644 --- a/src/renderers/dom/shared/ReactBrowserEventEmitter.js +++ b/src/renderers/dom/shared/ReactBrowserEventEmitter.js @@ -225,7 +225,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, { }, trapBubbledEvent: function(topLevelType, handlerBaseName, handle) { - return ReactDOMEventListener.trapBubbledEvent( + ReactDOMEventListener.trapBubbledEvent( topLevelType, handlerBaseName, handle, @@ -233,7 +233,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, { }, trapCapturedEvent: function(topLevelType, handlerBaseName, handle) { - return ReactDOMEventListener.trapCapturedEvent( + ReactDOMEventListener.trapCapturedEvent( topLevelType, handlerBaseName, handle, diff --git a/src/renderers/dom/shared/ReactDOMEventListener.js b/src/renderers/dom/shared/ReactDOMEventListener.js index 671588b6817..0b826ce599b 100644 --- a/src/renderers/dom/shared/ReactDOMEventListener.js +++ b/src/renderers/dom/shared/ReactDOMEventListener.js @@ -11,7 +11,6 @@ 'use strict'; -var EventListener = require('fbjs/lib/EventListener'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); var ReactFiberTreeReflection = require('ReactFiberTreeReflection'); var ReactGenericBatching = require('ReactGenericBatching'); @@ -138,12 +137,12 @@ var ReactDOMEventListener = { */ trapBubbledEvent: function(topLevelType, handlerBaseName, element) { if (!element) { - return null; + return; } - return EventListener.listen( - element, + element.addEventListener( handlerBaseName, ReactDOMEventListener.dispatchEvent.bind(null, topLevelType), + false, ); }, @@ -159,12 +158,12 @@ var ReactDOMEventListener = { */ trapCapturedEvent: function(topLevelType, handlerBaseName, element) { if (!element) { - return null; + return; } - return EventListener.capture( - element, + element.addEventListener( handlerBaseName, ReactDOMEventListener.dispatchEvent.bind(null, topLevelType), + true, ); }, From 984cf7f1b447347b67037dd1579d5b580226a69f Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 1 Sep 2017 11:10:55 -0700 Subject: [PATCH 3/4] Inline event removal code into Stack version Stack still depends on the return value. I just inline this into Stack version since we don't really care about it. --- .../dom/stack/client/ReactDOMComponent.js | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/renderers/dom/stack/client/ReactDOMComponent.js b/src/renderers/dom/stack/client/ReactDOMComponent.js index daf427fcc9e..d3eee492c6f 100644 --- a/src/renderers/dom/stack/client/ReactDOMComponent.js +++ b/src/renderers/dom/stack/client/ReactDOMComponent.js @@ -22,6 +22,7 @@ var EventPluginRegistry = require('EventPluginRegistry'); var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter'); var ReactDOMComponentFlags = require('ReactDOMComponentFlags'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); +var ReactDOMEventListener = require('ReactDOMEventListener'); var ReactDOMInput = require('ReactDOMInput'); var ReactDOMOption = require('ReactDOMOption'); var ReactDOMSelect = require('ReactDOMSelect'); @@ -276,11 +277,24 @@ function trapBubbledEventsLocal() { var node = getNode(inst); invariant(node, 'trapBubbledEvent(...): Requires node to be rendered.'); + function trapBubbledEvent(topLevelType, handlerBaseName, element) { + if (!element) { + return; + } + var callback = ReactDOMEventListener.dispatchEvent.bind(null, topLevelType); + element.addEventListener(handlerBaseName, callback, false); + return { + remove() { + element.removeEventListener(handlerBaseName, callback, false); + }, + }; + } + switch (inst._tag) { case 'iframe': case 'object': inst._wrapperState.listeners = [ - ReactBrowserEventEmitter.trapBubbledEvent('topLoad', 'load', node), + trapBubbledEvent('topLoad', 'load', node), ]; break; case 'video': @@ -290,47 +304,39 @@ function trapBubbledEventsLocal() { for (var event in mediaEvents) { if (mediaEvents.hasOwnProperty(event)) { inst._wrapperState.listeners.push( - ReactBrowserEventEmitter.trapBubbledEvent( - event, - mediaEvents[event], - node, - ), + trapBubbledEvent(event, mediaEvents[event], node), ); } } break; case 'source': inst._wrapperState.listeners = [ - ReactBrowserEventEmitter.trapBubbledEvent('topError', 'error', node), + trapBubbledEvent('topError', 'error', node), ]; break; case 'img': case 'image': inst._wrapperState.listeners = [ - ReactBrowserEventEmitter.trapBubbledEvent('topError', 'error', node), - ReactBrowserEventEmitter.trapBubbledEvent('topLoad', 'load', node), + trapBubbledEvent('topError', 'error', node), + trapBubbledEvent('topLoad', 'load', node), ]; break; case 'form': inst._wrapperState.listeners = [ - ReactBrowserEventEmitter.trapBubbledEvent('topReset', 'reset', node), - ReactBrowserEventEmitter.trapBubbledEvent('topSubmit', 'submit', node), + trapBubbledEvent('topReset', 'reset', node), + trapBubbledEvent('topSubmit', 'submit', node), ]; break; case 'input': case 'select': case 'textarea': inst._wrapperState.listeners = [ - ReactBrowserEventEmitter.trapBubbledEvent( - 'topInvalid', - 'invalid', - node, - ), + trapBubbledEvent('topInvalid', 'invalid', node), ]; break; case 'details': inst._wrapperState.listeners = [ - ReactBrowserEventEmitter.trapBubbledEvent('topToggle', 'toggle', node), + trapBubbledEvent('topToggle', 'toggle', node), ]; break; } From 5c79c32138a82ecfefdd4cef5ba0c63dedfe5bd3 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 1 Sep 2017 11:23:36 -0700 Subject: [PATCH 4/4] Remove fbjs/lib/focusNode dependency --- src/renderers/dom/shared/ReactInputSelection.js | 3 +-- src/renderers/dom/shared/utils/AutoFocusUtils.js | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/renderers/dom/shared/ReactInputSelection.js b/src/renderers/dom/shared/ReactInputSelection.js index 427e71f88a7..db4a4ca7213 100644 --- a/src/renderers/dom/shared/ReactInputSelection.js +++ b/src/renderers/dom/shared/ReactInputSelection.js @@ -15,7 +15,6 @@ var ReactDOMSelection = require('ReactDOMSelection'); var {ELEMENT_NODE} = require('HTMLNodeType'); var containsNode = require('fbjs/lib/containsNode'); -var focusNode = require('fbjs/lib/focusNode'); var getActiveElement = require('fbjs/lib/getActiveElement'); function isInDocument(node) { @@ -76,7 +75,7 @@ var ReactInputSelection = { } } - focusNode(priorFocusedElem); + priorFocusedElem.focus(); for (let i = 0; i < ancestors.length; i++) { const info = ancestors[i]; diff --git a/src/renderers/dom/shared/utils/AutoFocusUtils.js b/src/renderers/dom/shared/utils/AutoFocusUtils.js index 43a99bc3ead..207ac91d18e 100644 --- a/src/renderers/dom/shared/utils/AutoFocusUtils.js +++ b/src/renderers/dom/shared/utils/AutoFocusUtils.js @@ -13,11 +13,9 @@ var ReactDOMComponentTree = require('ReactDOMComponentTree'); -var focusNode = require('fbjs/lib/focusNode'); - var AutoFocusUtils = { focusDOMComponent: function() { - focusNode(ReactDOMComponentTree.getNodeFromInstance(this)); + ReactDOMComponentTree.getNodeFromInstance(this).focus(); }, };