diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index 78b38179ba614..6a88c7cf95c86 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -1439,6 +1439,7 @@ src/renderers/native/__tests__/ReactNativeEvents-test.js * handles events * handles events on text nodes * handles when a responder is unmounted while a touch sequence is in progress +* handles events without target src/renderers/native/__tests__/ReactNativeMount-test.js * should be able to create and render a native component diff --git a/src/renderers/native/ReactNativeEventEmitter.js b/src/renderers/native/ReactNativeEventEmitter.js index 6cea86f9d6ae6..42b69aa150663 100644 --- a/src/renderers/native/ReactNativeEventEmitter.js +++ b/src/renderers/native/ReactNativeEventEmitter.js @@ -102,11 +102,6 @@ var ReactNativeEventEmitter = { ) { var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT; var inst = ReactNativeComponentTree.getInstanceFromNode(rootNodeID); - if (!inst) { - // If the original instance is already gone, we don't have to dispatch - // any events. - return; - } ReactGenericBatching.batchedUpdates(function() { ReactNativeEventEmitter.handleTopLevel( topLevelType, diff --git a/src/renderers/native/__tests__/ReactNativeEvents-test.js b/src/renderers/native/__tests__/ReactNativeEvents-test.js index 783f4bab164c5..56206149a75e0 100644 --- a/src/renderers/native/__tests__/ReactNativeEvents-test.js +++ b/src/renderers/native/__tests__/ReactNativeEvents-test.js @@ -267,3 +267,97 @@ it('handles when a responder is unmounted while a touch sequence is in progress' expect(getResponderId()).toBe('two'); expect(log).toEqual(['two responder start']); }); + +it('handles events without target', () => { + var EventEmitter = RCTEventEmitter.register.mock.calls[0][0]; + var View = createReactNativeComponentClass({ + validAttributes: {id: true}, + uiViewClassName: 'View', + }); + + function getViewById(id) { + return UIManager.createView.mock.calls.find( + args => args[3] && args[3].id === id, + )[0]; + } + + function getResponderId() { + const responder = ResponderEventPlugin._getResponder(); + if (responder === null) { + return null; + } + const props = typeof responder.tag === 'number' + ? responder.memoizedProps + : responder._currentElement.props; + return props ? props.id : null; + } + + var log = []; + + function render(renderFirstComponent) { + ReactNative.render( + + + {renderFirstComponent + ? log.push('one responder end')} + onResponderStart={() => log.push('one responder start')} + onStartShouldSetResponder={() => true} + /> + : null} + + + log.push('two responder end')} + onResponderStart={() => log.push('two responder start')} + onStartShouldSetResponder={() => true} + /> + + , + 1, + ); + } + + render(true); + + EventEmitter.receiveTouches( + 'topTouchStart', + [{target: getViewById('one'), identifier: 17}], + [0], + ); + + // Unmounting component 'one'. + render(false); + + EventEmitter.receiveTouches( + 'topTouchEnd', + [{target: getViewById('one'), identifier: 17}], + [0], + ); + + expect(getResponderId()).toBe(null); + + EventEmitter.receiveTouches( + 'topTouchStart', + [{target: getViewById('two'), identifier: 18}], + [0], + ); + + expect(getResponderId()).toBe('two'); + + EventEmitter.receiveTouches( + 'topTouchEnd', + [{target: getViewById('two'), identifier: 18}], + [0], + ); + + expect(getResponderId()).toBe(null); + + expect(log).toEqual([ + 'one responder start', + 'two responder start', + 'two responder end', + ]); +});