Experimental Event API: add event component mount phase callback (#15480)
Dominic Gannaway committed
Apr 24, 2019 at 10:41 UTC
d3af2f2a5d7eee1cefb403eee7e67a4f292f5ca8
5 files changed
+65
-9
packages/react-dom/src/events/DOMEventResponderSystem.js
+17
-1
@@ -612,7 +612,10 @@ function triggerOwnershipListeners(): void {
612
const instance = listeningInstances[i];
613
const {props, responder, state} = instance;
614
currentInstance = instance;
615
- responder.onOwnershipChange(eventResponderContext, props, state);
615
+ const onOwnershipChange = responder.onOwnershipChange;
616
+ if (onOwnershipChange !== undefined) {
617
+ onOwnershipChange(eventResponderContext, props, state);
618
+ }
619
}
620
} finally {
621
currentInstance = previousInstance;
@@ -626,6 +629,19 @@ export function mountEventResponder(
629
if (responder.onOwnershipChange !== undefined) {
630
ownershipChangeListeners.add(eventComponentInstance);
631
}
632
+ const onMount = responder.onMount;
633
+ if (onMount !== undefined) {
634
+ let {props, state} = eventComponentInstance;
635
+ currentEventQueue = createEventQueue();
636
+ currentInstance = eventComponentInstance;
637
+ try {
638
+ onMount(eventResponderContext, props, state);
639
+ } finally {
640
+ currentEventQueue = null;
641
+ currentInstance = null;
642
+ currentTimers = null;
643
+ }
644
+ }
645
}
646
647
export function unmountEventResponder(
packages/react-dom/src/events/__tests__/DOMEventResponderSystem-test.internal.js
+32
-1
@@ -21,6 +21,7 @@ function createReactEventComponent(
21
onEvent,
22
onEventCapture,
23
onRootEvent,
24
+ onMount,
25
onUnmount,
26
onOwnershipChange,
27
stopLocalPropagation,
@@ -32,6 +33,7 @@ function createReactEventComponent(
33
onEvent,
34
onEventCapture,
35
onRootEvent,
36
+ onMount,
37
onUnmount,
38
onOwnershipChange,
39
stopLocalPropagation: stopLocalPropagation || false,
@@ -395,6 +397,7 @@ describe('DOMEventResponderSystem', () => {
397
undefined,
398
undefined,
399
undefined,
400
+ undefined,
401
true,
402
);
403
@@ -554,6 +557,31 @@ describe('DOMEventResponderSystem', () => {
557
]);
558
});
559
560
+ it('the event responder onMount() function should fire', () => {
561
+ let onMountFired = 0;
562
+
563
+ const EventComponent = createReactEventComponent(
564
+ [],
565
+ undefined,
566
+ undefined,
567
+ undefined,
568
+ undefined,
569
+ undefined,
570
+ () => {
571
+ onMountFired++;
572
+ },
573
+ );
574
+
575
+ const Test = () => (
576
+ <EventComponent>
577
+ <button />
578
+ </EventComponent>
579
+ );
580
+
581
+ ReactDOM.render(<Test />, container);
582
+ expect(onMountFired).toEqual(1);
583
+ });
584
+
585
it('the event responder onUnmount() function should fire', () => {
586
let onUnmountFired = 0;
587
@@ -563,7 +591,8 @@ describe('DOMEventResponderSystem', () => {
591
undefined,
592
undefined,
593
undefined,
566
- (event, context, props, state) => {},
594
+ undefined,
595
+ undefined,
596
() => {
597
onUnmountFired++;
598
},
@@ -592,6 +621,7 @@ describe('DOMEventResponderSystem', () => {
621
undefined,
622
undefined,
623
undefined,
624
+ undefined,
625
(context, props, state) => {
626
counter += state.incrementAmount;
627
},
@@ -623,6 +653,7 @@ describe('DOMEventResponderSystem', () => {
653
undefined,
654
undefined,
655
undefined,
656
+ undefined,
657
() => {
658
onOwnershipChangeFired++;
659
},
packages/react-reconciler/src/ReactFiberCommitWork.js
+8
-1
@@ -98,6 +98,7 @@ import {
98
unhideTextInstance,
99
unmountEventComponent,
100
commitEventTarget,
101
+ mountEventComponent,
102
} from './ReactFiberHostConfig';
103
import {
104
captureCommitPhaseError,
@@ -595,6 +596,7 @@ function commitLifeCycles(
596
case SuspenseComponent:
597
case IncompleteClassComponent:
598
case EventTarget:
599
+ case EventComponent:
600
break;
601
default: {
602
invariant(
@@ -835,7 +837,8 @@ function commitContainer(finishedWork: Fiber) {
837
case ClassComponent:
838
case HostComponent:
839
case HostText:
838
- case EventTarget: {
840
+ case EventTarget:
841
+ case EventComponent: {
842
return;
843
}
844
case HostRoot:
@@ -1255,6 +1258,10 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1258
case IncompleteClassComponent: {
1259
return;
1260
}
1261
+ case EventComponent: {
1262
+ mountEventComponent(finishedWork.stateNode);
1263
+ return;
1264
+ }
1265
default: {
1266
invariant(
1267
false,
packages/react-reconciler/src/ReactFiberCompleteWork.js
+1
-3
@@ -68,7 +68,6 @@ import {
68
createContainerChildSet,
69
appendChildToContainerChildSet,
70
finalizeContainerChildren,
71
- mountEventComponent,
71
updateEventComponent,
72
handleEventTarget,
73
} from './ReactFiberHostConfig';
@@ -813,14 +812,13 @@ function completeWork(
812
responderState = responder.createInitialState(newProps);
813
}
814
eventComponentInstance = workInProgress.stateNode = {
816
- context: null,
815
props: newProps,
816
responder,
817
rootEventTypes: null,
818
rootInstance: rootContainerInstance,
819
state: responderState,
820
};
823
- mountEventComponent(eventComponentInstance);
821
+ markUpdate(workInProgress);
822
} else {
823
// Update the props on the event component state node
824
eventComponentInstance.props = newProps;
packages/shared/ReactTypes.js
+7
-3
@@ -108,12 +108,17 @@ export type ReactEventResponder = {
108
props: null | Object,
109
state: null | Object,
110
) => void,
111
- onUnmount: (
111
+ onMount?: (
112
context: ReactResponderContext,
113
props: null | Object,
114
state: null | Object,
115
) => void,
116
- onOwnershipChange: (
116
+ onUnmount?: (
117
+ context: ReactResponderContext,
118
+ props: null | Object,
119
+ state: null | Object,
120
+ ) => void,
121
+ onOwnershipChange?: (
122
context: ReactResponderContext,
123
props: null | Object,
124
state: null | Object,
@@ -121,7 +126,6 @@ export type ReactEventResponder = {
126
};
127
128
export type ReactEventComponentInstance = {|
124
- context: null | Object,
129
props: null | Object,
130
responder: ReactEventResponder,
131
rootEventTypes: null | Set<string>,