@samitouri / QOS-React-2 / commits / aa519c17cc

[Flare] Add currentTarget and unify RN and DOM codepaths (#16066)

Dominic Gannaway committed Jul 8, 2019 at 11:50 UTC aa519c17cc10c071906d06abeade9e1bd0ed3dc1
8 files changed +215 -278
packages/react-dom/src/events/DOMEventResponderSystem.js
+82 -134
@@ -372,29 +372,6 @@ const eventResponderContext: ReactDOMResponderContext = {
372 },
373 getActiveDocument,
374 objectAssign: Object.assign,
375 - getEventCurrentTarget(event: ReactDOMResponderEvent): Element {
376 - validateResponderContext();
377 - const target = event.target;
378 - let fiber = getClosestInstanceFromNode(target);
379 - let hostComponent = target;
380 - const currentResponder = ((currentInstance: any): ReactDOMEventComponentInstance)
381 - .responder;
382 -
383 - while (fiber !== null) {
384 - const stateNode = fiber.stateNode;
385 - if (
386 - fiber.tag === EventComponent &&
387 - (stateNode === null || stateNode.responder === currentResponder)
388 - ) {
389 - break;
390 - }
391 - if (fiber.tag === HostComponent) {
392 - hostComponent = fiber.stateNode;
393 - }
394 - fiber = fiber.return;
395 - }
396 - return ((hostComponent: any): Element);
397 - },
375 getTimeStamp(): number {
376 validateResponderContext();
377 return currentTimeStamp;
@@ -553,6 +530,7 @@ function createDOMResponderEvent(
530 }
531
532 return {
533 + currentTarget: nativeEventTarget,
534 nativeEvent: nativeEvent,
535 passive,
536 passiveSupported,
@@ -650,11 +628,12 @@ function getDOMTargetEventTypesSet(
628 return cachedSet;
629 }
630
653 -function storeTargetEventResponderInstance(
631 +function handleTargetEventResponderInstance(
632 listeningName: string,
633 + responderEvent: ReactDOMResponderEvent,
634 eventComponentInstance: ReactDOMEventComponentInstance,
656 - eventResponderInstances: Array<ReactDOMEventComponentInstance>,
657 - eventComponentResponders: null | Set<ReactDOMEventResponder>,
635 + hookComponentResponderValidation: null | Set<ReactDOMEventResponder>,
636 + propagatedEventResponders: null | Set<ReactDOMEventResponder>,
637 ): void {
638 const responder = eventComponentInstance.responder;
639 const targetEventTypes = responder.targetEventTypes;
@@ -662,74 +641,34 @@ function storeTargetEventResponderInstance(
641 if (targetEventTypes !== undefined) {
642 const targetEventTypesSet = getDOMTargetEventTypesSet(targetEventTypes);
643 if (targetEventTypesSet.has(listeningName)) {
665 - eventResponderInstances.push(eventComponentInstance);
666 - if (eventComponentResponders !== null) {
667 - eventComponentResponders.add(responder);
644 + if (hookComponentResponderValidation !== null) {
645 + hookComponentResponderValidation.add(responder);
646 }
669 - }
670 - }
671 -}
672 -
673 -function getTargetEventResponderInstances(
674 - listeningName: string,
675 - targetFiber: null | Fiber,
676 -): Array<ReactDOMEventComponentInstance> {
677 - // We use this to know if we should check add hooks. If there are
678 - // no event targets, then we don't add the hook forms.
679 - const eventComponentResponders = new Set();
680 - const eventResponderInstances = [];
681 - let node = targetFiber;
682 - while (node !== null) {
683 - // Traverse up the fiber tree till we find event component fibers.
684 - const tag = node.tag;
685 - const dependencies = node.dependencies;
686 - if (tag === EventComponent) {
687 - const eventComponentInstance = node.stateNode;
688 - // Switch to the current fiber tree
689 - node = eventComponentInstance.currentFiber;
690 - storeTargetEventResponderInstance(
691 - listeningName,
692 - eventComponentInstance,
693 - eventResponderInstances,
694 - eventComponentResponders,
695 - );
696 - } else if (tag === FunctionComponent && dependencies !== null) {
697 - const events = dependencies.events;
698 - if (events !== null) {
699 - for (let i = 0; i < events.length; i++) {
700 - const eventComponentInstance = events[i];
701 - if (eventComponentResponders.has(eventComponentInstance.responder)) {
702 - storeTargetEventResponderInstance(
703 - listeningName,
704 - eventComponentInstance,
705 - eventResponderInstances,
706 - null,
707 - );
708 - }
647 + const {isHook, props, state} = eventComponentInstance;
648 + const onEvent = responder.onEvent;
649 + if (onEvent !== undefined) {
650 + if (
651 + shouldSkipEventComponent(
652 + eventComponentInstance,
653 + ((responder: any): ReactDOMEventResponder),
654 + propagatedEventResponders,
655 + isHook,
656 + )
657 + ) {
658 + return;
659 + }
660 + currentInstance = eventComponentInstance;
661 + currentlyInHook = isHook;
662 + onEvent(responderEvent, eventResponderContext, props, state);
663 + if (!isHook) {
664 + checkForLocalPropagationContinuation(
665 + responder,
666 + ((propagatedEventResponders: any): Set<ReactDOMEventResponder>),
667 + );
668 }
669 }
670 }
712 - node = node.return;
713 - }
714 - return eventResponderInstances;
715 -}
716 -
717 -function getRootEventResponderInstances(
718 - listeningName: string,
719 -): Array<ReactDOMEventComponentInstance> {
720 - const eventResponderInstances = [];
721 - const rootEventInstances = rootEventTypesToEventComponentInstances.get(
722 - listeningName,
723 - );
724 - if (rootEventInstances !== undefined) {
725 - const rootEventComponentInstances = Array.from(rootEventInstances);
726 -
727 - for (let i = 0; i < rootEventComponentInstances.length; i++) {
728 - const rootEventComponentInstance = rootEventComponentInstances[i];
729 - eventResponderInstances.push(rootEventComponentInstance);
730 - }
671 }
732 - return eventResponderInstances;
672 }
673
674 function shouldSkipEventComponent(
@@ -778,10 +717,6 @@ function traverseAndHandleEventResponderInstances(
717 // - Bubble target phase
718 // - Root phase
719
781 - const targetEventResponderInstances = getTargetEventResponderInstances(
782 - listeningName,
783 - targetFiber,
784 - );
720 const responderEvent = createDOMResponderEvent(
721 ((topLevelType: any): string),
722 nativeEvent,
@@ -790,57 +725,70 @@ function traverseAndHandleEventResponderInstances(
725 isPassiveSupported,
726 );
727 const propagatedEventResponders: Set<ReactDOMEventResponder> = new Set();
793 - let length = targetEventResponderInstances.length;
794 - let i;
728 +
729 + // We use this to know if we should check add hooks. If there are
730 + // no event targets, then we don't add the hook forms.
731 + const hookComponentResponderValidation = new Set();
732
733 // Bubbled event phases have the notion of local propagation.
734 // This means that the propgation chain can be stopped part of the the way
798 - // through processing event component instances. The major difference to other
799 - // events systems is that the stopping of propagation is localized to a single
800 - // phase, rather than both phases.
801 - if (length > 0) {
802 - // Bubble target phase
803 - for (i = 0; i < length; i++) {
804 - const targetEventResponderInstance = targetEventResponderInstances[i];
805 - const {isHook, props, responder, state} = targetEventResponderInstance;
806 - const eventListener = responder.onEvent;
807 - if (eventListener !== undefined) {
808 - if (
809 - shouldSkipEventComponent(
810 - targetEventResponderInstance,
811 - ((responder: any): ReactDOMEventResponder),
812 - propagatedEventResponders,
813 - isHook,
814 - )
815 - ) {
816 - continue;
817 - }
818 - currentInstance = targetEventResponderInstance;
819 - currentlyInHook = isHook;
820 - eventListener(responderEvent, eventResponderContext, props, state);
821 - if (!isHook) {
822 - checkForLocalPropagationContinuation(
823 - responder,
824 - propagatedEventResponders,
825 - );
735 + // through processing event component instances.
736 + let node = targetFiber;
737 + while (node !== null) {
738 + const {dependencies, stateNode, tag} = node;
739 + if (tag === HostComponent) {
740 + responderEvent.currentTarget = stateNode;
741 + } else if (tag === EventComponent) {
742 + const eventComponentInstance = stateNode;
743 + // Switch to the current fiber tree
744 + node = eventComponentInstance.currentFiber;
745 + handleTargetEventResponderInstance(
746 + listeningName,
747 + responderEvent,
748 + eventComponentInstance,
749 + hookComponentResponderValidation,
750 + propagatedEventResponders,
751 + );
752 + } else if (tag === FunctionComponent && dependencies !== null) {
753 + const events = dependencies.events;
754 + if (events !== null) {
755 + for (let i = 0; i < events.length; i++) {
756 + const eventComponentInstance = events[i];
757 + if (
758 + hookComponentResponderValidation.has(
759 + eventComponentInstance.responder,
760 + )
761 + ) {
762 + handleTargetEventResponderInstance(
763 + listeningName,
764 + responderEvent,
765 + eventComponentInstance,
766 + null,
767 + null,
768 + );
769 + }
770 }
771 }
772 }
773 + node = node.return;
774 }
775 + // Reset currentTarget to be null
776 + responderEvent.currentTarget = null;
777 // Root phase
831 - const rootEventResponderInstances = getRootEventResponderInstances(
778 + const rootEventInstances = rootEventTypesToEventComponentInstances.get(
779 listeningName,
780 );
834 - length = rootEventResponderInstances.length;
835 - if (length > 0) {
836 - for (i = 0; i < length; i++) {
837 - const rootEventResponderInstance = rootEventResponderInstances[i];
838 - const {isHook, props, responder, state} = rootEventResponderInstance;
839 - const eventListener = responder.onRootEvent;
840 - if (eventListener !== undefined) {
781 + if (rootEventInstances !== undefined) {
782 + const rootEventComponentInstances = Array.from(rootEventInstances);
783 +
784 + for (let i = 0; i < rootEventComponentInstances.length; i++) {
785 + const rootEventComponentInstance = rootEventComponentInstances[i];
786 + const {isHook, props, responder, state} = rootEventComponentInstance;
787 + const onRootEvent = responder.onRootEvent;
788 + if (onRootEvent !== undefined) {
789 if (
790 shouldSkipEventComponent(
843 - rootEventResponderInstance,
791 + rootEventComponentInstance,
792 responder,
793 null,
794 isHook,
@@ -848,9 +796,9 @@ function traverseAndHandleEventResponderInstances(
796 ) {
797 continue;
798 }
851 - currentInstance = rootEventResponderInstance;
799 + currentInstance = rootEventComponentInstance;
800 currentlyInHook = isHook;
853 - eventListener(responderEvent, eventResponderContext, props, state);
801 + onRootEvent(responderEvent, eventResponderContext, props, state);
802 }
803 }
804 }
packages/react-events/src/dom/Focus.js
+4 -2
@@ -207,8 +207,10 @@ function handleRootPointerEvent(
207
208 // Focus should stop being visible if a pointer is used on the element
209 // after it was focused using a keyboard.
210 + const focusTarget = state.focusTarget;
211 if (
211 - state.focusTarget === context.getEventCurrentTarget(event) &&
212 + focusTarget !== null &&
213 + context.isTargetWithinNode(event.target, focusTarget) &&
214 (type === 'mousedown' || type === 'touchstart' || type === 'pointerdown')
215 ) {
216 dispatchFocusVisibleOutEvent(context, props, state);
@@ -253,7 +255,7 @@ const FocusResponder: ReactDOMEventResponder = {
255 if (!state.isFocused) {
256 // Limit focus events to the direct child of the event component.
257 // Browser focus is not expected to bubble.
256 - state.focusTarget = context.getEventCurrentTarget(event);
258 + state.focusTarget = event.currentTarget;
259 if (state.focusTarget === target) {
260 state.isFocused = true;
261 state.isLocalFocusVisible = isGlobalFocusVisible;
packages/react-events/src/dom/Hover.js
+1 -1
@@ -321,7 +321,7 @@ const HoverResponder: ReactDOMEventResponder = {
321 if (isEmulatedMouseEvent(event, state)) {
322 return;
323 }
324 - state.hoverTarget = context.getEventCurrentTarget(event);
324 + state.hoverTarget = event.currentTarget;
325 state.ignoreEmulatedMouseEvents = true;
326 dispatchHoverStartEvents(event, context, props, state);
327 }
packages/react-events/src/dom/Press.js
+24 -13
@@ -57,7 +57,7 @@ type PressState = {
57 isPressWithinResponderRegion: boolean,
58 longPressTimeout: null | number,
59 pointerType: PointerType,
60 - pressTarget: null | Element,
60 + pressTarget: null | Element | Document,
61 pressEndTimeout: null | number,
62 pressStartTimeout: null | number,
63 responderRegionOnActivation: null | $ReadOnly<{|
@@ -619,6 +619,11 @@ function handleStopPropagation(
619 }
620 }
621
622 +function targetIsDocument(target: null | Node): boolean {
623 + // When target is null, it is the root
624 + return target === null || target.nodeType === 9;
625 +}
626 +
627 const PressResponder: ReactDOMEventResponder = {
628 displayName: 'Press',
629 targetEventTypes,
@@ -691,7 +696,7 @@ const PressResponder: ReactDOMEventResponder = {
696 // We set these here, before the button check so we have this
697 // data around for handling of the context menu
698 state.pointerType = pointerType;
694 - state.pressTarget = context.getEventCurrentTarget(event);
699 + const pressTarget = (state.pressTarget = event.currentTarget);
700 if (isPointerEvent) {
701 state.activePointerId = pointerId;
702 } else if (isTouchEvent) {
@@ -712,12 +717,14 @@ const PressResponder: ReactDOMEventResponder = {
717 ) {
718 return;
719 }
715 -
716 - state.responderRegionOnActivation = calculateResponderRegion(
717 - context,
718 - state.pressTarget,
719 - props,
720 - );
720 + // Exclude document targets
721 + if (!targetIsDocument(pressTarget)) {
722 + state.responderRegionOnActivation = calculateResponderRegion(
723 + context,
724 + ((pressTarget: any): Element),
725 + props,
726 + );
727 + }
728 state.responderRegionOnDeactivation = null;
729 state.isPressWithinResponderRegion = true;
730 dispatchPressStartEvents(event, context, props, state);
@@ -824,11 +831,13 @@ const PressResponder: ReactDOMEventResponder = {
831 }
832 state.touchEvent = touchEvent;
833 }
834 + const pressTarget = state.pressTarget;
835
836 if (
829 - state.pressTarget !== null &&
837 + pressTarget !== null &&
838 + !targetIsDocument(pressTarget) &&
839 (pointerType !== 'mouse' ||
831 - !context.isTargetWithinNode(target, state.pressTarget))
840 + !context.isTargetWithinNode(target, pressTarget))
841 ) {
842 // Calculate the responder region we use for deactivation, as the
843 // element dimensions may have changed since activation.
@@ -934,14 +943,16 @@ const PressResponder: ReactDOMEventResponder = {
943 }
944
945 const wasLongPressed = state.isLongPressed;
946 + const pressTarget = state.pressTarget;
947 dispatchPressEndEvents(event, context, props, state);
948
939 - if (state.pressTarget !== null && props.onPress) {
949 + if (pressTarget !== null && props.onPress) {
950 if (
951 !isKeyboardEvent &&
942 - state.pressTarget !== null &&
952 + pressTarget !== null &&
953 + !targetIsDocument(pressTarget) &&
954 (pointerType !== 'mouse' ||
944 - !context.isTargetWithinNode(target, state.pressTarget))
955 + !context.isTargetWithinNode(target, pressTarget))
956 ) {
957 // If the event target isn't within the press target, check if we're still
958 // within the responder region. The region may have changed if the
packages/react-events/src/rn/Press.js
+1 -3
@@ -537,9 +537,7 @@ const PressResponder: ReactNativeEventResponder = {
537 if (type === 'topTouchStart') {
538 if (!state.isPressed) {
539 state.pointerType = 'touch';
540 - const pressTarget = (state.pressTarget = context.getEventCurrentTarget(
541 - event,
542 - ));
540 + const pressTarget = (state.pressTarget = event.currentTarget);
541
542 const touchEvent = getTouchFromPressEvent(nativeEvent);
543 if (touchEvent === null) {
packages/react-native-renderer/src/ReactFabricEventResponderSystem.js
+101 -121
@@ -7,7 +7,11 @@
7 * @flow
8 */
9
10 -import {EventComponent, HostComponent} from 'shared/ReactWorkTags';
10 +import {
11 + EventComponent,
12 + HostComponent,
13 + FunctionComponent,
14 +} from 'shared/ReactWorkTags';
15 import type {Fiber} from 'react-reconciler/src/ReactFiber';
16 import {
17 batchedEventUpdates,
@@ -192,31 +196,6 @@ const eventResponderContext: ReactNativeResponderContext = {
196 }
197 return false;
198 },
195 - getEventCurrentTarget(
196 - event: ReactNativeResponderEvent,
197 - ): ReactNativeEventTarget {
198 - validateResponderContext();
199 - const target = event.target;
200 - let fiber = getFiberFromTarget(target);
201 - let hostComponent = target;
202 - const currentResponder = ((currentInstance: any): ReactNativeEventComponentInstance)
203 - .responder;
204 -
205 - while (fiber !== null) {
206 - const stateNode = fiber.stateNode;
207 - if (
208 - fiber.tag === EventComponent &&
209 - (stateNode === null || stateNode.responder === currentResponder)
210 - ) {
211 - break;
212 - }
213 - if (fiber.tag === HostComponent) {
214 - hostComponent = fiber.stateNode;
215 - }
216 - fiber = fiber.return;
217 - }
218 - return ((hostComponent: any): ReactNativeEventTarget);
219 - },
199 getTargetBoundingRect(
200 target: ReactNativeEventTarget,
201 callback: ({
@@ -320,7 +299,7 @@ function getFiberFromTarget(
299 if (target === null) {
300 return null;
301 }
323 - return ((target.canonical._internalInstanceHandle: any): Fiber);
302 + return ((target.canonical._internalInstanceHandle: any): Fiber) || null;
303 }
304
305 function processTimers(
@@ -355,15 +334,12 @@ function createFabricResponderEvent(
334 nativeEvent: ReactFaricEvent,
335 target: null | ReactNativeEventTarget,
336 ): ReactNativeResponderEvent {
358 - const responderEvent = {
337 + return {
338 + currentTarget: target,
339 nativeEvent,
340 target,
341 type: topLevelType,
342 };
363 - if (__DEV__) {
364 - Object.freeze(responderEvent);
365 - }
366 - return responderEvent;
343 }
344
345 function validateResponderContext(): void {
@@ -490,35 +466,6 @@ function getFabricTargetEventTypesSet(
466 return cachedSet;
467 }
468
493 -// TODO this function is almost an exact copy of the DOM version, we should
494 -// somehow share the logic
495 -function getTargetEventResponderInstances(
496 - topLevelType: ReactNativeEventResponderEventType,
497 - targetFiber: null | Fiber,
498 -): Array<ReactNativeEventComponentInstance> {
499 - const eventResponderInstances = [];
500 - let node = targetFiber;
501 - while (node !== null) {
502 - // Traverse up the fiber tree till we find event component fibers.
503 - if (node.tag === EventComponent) {
504 - const eventComponentInstance = node.stateNode;
505 - const responder = eventComponentInstance.responder;
506 - const targetEventTypes = responder.targetEventTypes;
507 - // Validate the target event type exists on the responder
508 - if (targetEventTypes !== undefined) {
509 - const targetEventTypesSet = getFabricTargetEventTypesSet(
510 - targetEventTypes,
511 - );
512 - if (targetEventTypesSet.has(topLevelType)) {
513 - eventResponderInstances.push(eventComponentInstance);
514 - }
515 - }
516 - }
517 - node = node.return;
518 - }
519 - return eventResponderInstances;
520 -}
521 -
469 // TODO this function is almost an exact copy of the DOM version, we should
470 // somehow share the logic
471 function shouldSkipEventComponent(
@@ -551,22 +498,47 @@ function checkForLocalPropagationContinuation(
498
499 // TODO this function is almost an exact copy of the DOM version, we should
500 // somehow share the logic
554 -function getRootEventResponderInstances(
555 - topLevelType: string,
556 -): Array<ReactNativeEventComponentInstance> {
557 - const eventResponderInstances = [];
558 - const rootEventInstances = rootEventTypesToEventComponentInstances.get(
559 - topLevelType,
560 - );
561 - if (rootEventInstances !== undefined) {
562 - const rootEventComponentInstances = Array.from(rootEventInstances);
563 -
564 - for (let i = 0; i < rootEventComponentInstances.length; i++) {
565 - const rootEventComponentInstance = rootEventComponentInstances[i];
566 - eventResponderInstances.push(rootEventComponentInstance);
501 +function handleTargetEventResponderInstance(
502 + topLevelType: ReactNativeEventResponderEventType,
503 + responderEvent: ReactNativeResponderEvent,
504 + eventComponentInstance: ReactNativeEventComponentInstance,
505 + hookComponentResponderValidation: null | Set<ReactNativeEventResponder>,
506 + propagatedEventResponders: null | Set<ReactNativeEventResponder>,
507 +): void {
508 + const responder = eventComponentInstance.responder;
509 + const targetEventTypes = responder.targetEventTypes;
510 + // Validate the target event type exists on the responder
511 + if (targetEventTypes !== undefined) {
512 + const targetEventTypesSet = getFabricTargetEventTypesSet(targetEventTypes);
513 + if (targetEventTypesSet.has(topLevelType)) {
514 + if (hookComponentResponderValidation !== null) {
515 + hookComponentResponderValidation.add(responder);
516 + }
517 + const {isHook, props, state} = eventComponentInstance;
518 + const eventListener = responder.onEvent;
519 + if (eventListener !== undefined) {
520 + if (
521 + shouldSkipEventComponent(
522 + eventComponentInstance,
523 + ((responder: any): ReactNativeEventResponder),
524 + propagatedEventResponders,
525 + isHook,
526 + )
527 + ) {
528 + return;
529 + }
530 + currentInstance = eventComponentInstance;
531 + currentlyInHook = isHook;
532 + eventListener(responderEvent, eventResponderContext, props, state);
533 + if (!isHook) {
534 + checkForLocalPropagationContinuation(
535 + responder,
536 + ((propagatedEventResponders: any): Set<ReactNativeEventResponder>),
537 + );
538 + }
539 + }
540 }
541 }
569 - return eventResponderInstances;
542 }
543
544 // TODO this function is almost an exact copy of the DOM version, we should
@@ -580,10 +552,6 @@ function traverseAndHandleEventResponderInstances(
552 // - Bubble target phase
553 // - Root phase
554
583 - const targetEventResponderInstances = getTargetEventResponderInstances(
584 - topLevelType,
585 - targetFiber,
586 - );
555 const responderEvent = createFabricResponderEvent(
556 topLevelType,
557 nativeEvent,
@@ -592,58 +560,70 @@ function traverseAndHandleEventResponderInstances(
560 : null,
561 );
562 const propagatedEventResponders: Set<ReactNativeEventResponder> = new Set();
595 - let length = targetEventResponderInstances.length;
596 - let i;
563 +
564 + // We use this to know if we should check add hooks. If there are
565 + // no event targets, then we don't add the hook forms.
566 + const hookComponentResponderValidation = new Set();
567
568 // Bubbled event phases have the notion of local propagation.
569 // This means that the propgation chain can be stopped part of the the way
600 - // through processing event component instances. The major difference to other
601 - // events systems is that the stopping of propagation is localized to a single
602 - // phase, rather than both phases.
603 - if (length > 0) {
604 - // Bubble target phase
605 - for (i = 0; i < length; i++) {
606 - const targetEventResponderInstance = targetEventResponderInstances[i];
607 - const {isHook, responder, props, state} = targetEventResponderInstance;
608 - const eventListener = ((responder: any): ReactNativeEventResponder)
609 - .onEvent;
610 - if (eventListener !== undefined) {
611 - if (
612 - shouldSkipEventComponent(
613 - targetEventResponderInstance,
614 - ((responder: any): ReactNativeEventResponder),
615 - propagatedEventResponders,
616 - isHook,
617 - )
618 - ) {
619 - continue;
620 - }
621 - currentInstance = targetEventResponderInstance;
622 - currentlyInHook = isHook;
623 - eventListener(responderEvent, eventResponderContext, props, state);
624 - if (!isHook) {
625 - checkForLocalPropagationContinuation(
626 - ((responder: any): ReactNativeEventResponder),
627 - propagatedEventResponders,
628 - );
570 + // through processing event component instances.
571 + let node = targetFiber;
572 + while (node !== null) {
573 + const {dependencies, stateNode, tag} = node;
574 + if (tag === HostComponent) {
575 + responderEvent.currentTarget = stateNode;
576 + } else if (tag === EventComponent) {
577 + const eventComponentInstance = stateNode;
578 + // Switch to the current fiber tree
579 + node = eventComponentInstance.currentFiber;
580 + handleTargetEventResponderInstance(
581 + topLevelType,
582 + responderEvent,
583 + eventComponentInstance,
584 + hookComponentResponderValidation,
585 + propagatedEventResponders,
586 + );
587 + } else if (tag === FunctionComponent && dependencies !== null) {
588 + const events = dependencies.events;
589 + if (events !== null) {
590 + for (let i = 0; i < events.length; i++) {
591 + const eventComponentInstance = events[i];
592 + if (
593 + hookComponentResponderValidation.has(
594 + eventComponentInstance.responder,
595 + )
596 + ) {
597 + handleTargetEventResponderInstance(
598 + topLevelType,
599 + responderEvent,
600 + eventComponentInstance,
601 + null,
602 + null,
603 + );
604 + }
605 }
606 }
607 }
608 + node = node.return;
609 }
610 + // Reset currentTarget to be null
611 + responderEvent.currentTarget = null;
612 // Root phase
634 - const rootEventResponderInstances = getRootEventResponderInstances(
613 + const rootEventInstances = rootEventTypesToEventComponentInstances.get(
614 topLevelType,
615 );
637 - length = rootEventResponderInstances.length;
638 - if (length > 0) {
639 - for (i = 0; i < length; i++) {
640 - const rootEventResponderInstance = rootEventResponderInstances[i];
641 - const {isHook, props, responder, state} = rootEventResponderInstance;
642 - const eventListener = responder.onRootEvent;
643 - if (eventListener !== undefined) {
616 + if (rootEventInstances !== undefined) {
617 + const rootEventComponentInstances = Array.from(rootEventInstances);
618 +
619 + for (let i = 0; i < rootEventComponentInstances.length; i++) {
620 + const rootEventComponentInstance = rootEventComponentInstances[i];
621 + const {isHook, props, responder, state} = rootEventComponentInstance;
622 + const onRootEvent = responder.onRootEvent;
623 + if (onRootEvent !== undefined) {
624 if (
625 shouldSkipEventComponent(
646 - rootEventResponderInstance,
626 + rootEventComponentInstance,
627 responder,
628 null,
629 isHook,
@@ -651,9 +631,9 @@ function traverseAndHandleEventResponderInstances(
631 ) {
632 continue;
633 }
654 - currentInstance = rootEventResponderInstance;
634 + currentInstance = rootEventComponentInstance;
635 currentlyInHook = isHook;
656 - eventListener(responderEvent, eventResponderContext, props, state);
636 + onRootEvent(responderEvent, eventResponderContext, props, state);
637 }
638 }
639 }
packages/react-native-renderer/src/ReactNativeTypes.js
+1 -3
@@ -199,6 +199,7 @@ export type ReactFaricEvent = {
199 };
200
201 export type ReactNativeResponderEvent = {
202 + currentTarget: null | ReactNativeEventTarget,
203 nativeEvent: ReactFaricEvent,
204 target: null | ReactNativeEventTarget,
205 type: ReactNativeEventResponderEventType,
@@ -229,9 +230,6 @@ export type ReactNativeResponderContext = {
230 removeRootEventTypes: (
231 rootEventTypes: Array<ReactNativeEventResponderEventType>,
232 ) => void,
232 - getEventCurrentTarget(
233 - event: ReactNativeResponderEvent,
234 - ): ReactNativeEventTarget,
233 setTimeout: (func: () => void, timeout: number) => number,
234 clearTimeout: (timerId: number) => void,
235 getTimeStamp: () => number,
packages/shared/ReactDOMTypes.js
+1 -1
@@ -28,6 +28,7 @@ export type PointerType =
28 | 'trackpad';
29
30 export type ReactDOMResponderEvent = {
31 + currentTarget: null | Element | Document,
32 nativeEvent: AnyNativeEvent,
33 passive: boolean,
34 passiveSupported: boolean,
@@ -75,7 +76,6 @@ export type ReactDOMResponderContext = {
76 getFocusableElementsInScope(): Array<HTMLElement>,
77 getActiveDocument(): Document,
78 objectAssign: Function,
78 - getEventCurrentTarget(event: ReactDOMResponderEvent): Element,
79 getTimeStamp: () => number,
80 isTargetWithinHostComponent: (
81 target: Element | Document,