-
Notifications
You must be signed in to change notification settings - Fork 50.4k
Remove dependency on fbjs/lib/EventListener and fbjs/lib/focusNode #10592
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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( | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only case in which this wouldn't be equivalent is if
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to throw if
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think EventListener gets shimmed in www?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There exists a mobile version that wraps into
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm curious about when
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think an invariant is very valuable here because it's a leaf code path (throws immediately with a very obvious message).
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aah, I get it now. We leave
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @gaearon what throws immediately? If this is protected from null elements earlier in the code path could we just remove the falsy check?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @aweary Yes I think we can. |
||
| 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, | ||
| ); | ||
| }, | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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]); | ||
| } | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Deleted this aggregation because it goes through the same code path now. |
||
|
|
||
| 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(); | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I deleted this set of assertions. I'm not sure what they're supposed to be testing but they didn't work in the first place. The intention was probably to match whether an array contains an item, but [ 'topBlur',
'topChange',
'topClick',
'topFocus',
'topInput',
'topKeyDown',
'topKeyUp',
'topSelectionChange' ]but value being tested looks like 'blur'Maybe there's some better way to test this but I figured just asserting the count is enough. |
||
| } | ||
| expect(document.addEventListener.calls.count()).toEqual( | ||
| dependencies.length, | ||
| ); | ||
| }); | ||
|
|
||
| it('should bubble onTouchTap', () => { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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(); | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is Stack-only codepath. |
||
| }, | ||
| }; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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), | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Stack code still relies on return value for unsubscribing. Fiber doesn't. I inlined the old Stack-friendly version right into Stack.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How does Fiber handle removing those listeners on unmount? Does it just not do that anymore?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it doesn't. Relies on GC to clean them up.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At some point I need to circle back about this on #9333. We need local listeners and I'm trying to figure out the best way to clean them up. |
||
| ]; | ||
| 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; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fiber codebase doesn't use return value (which is always allocating an object).