@samitouri / QOS-React / commits / aece8119cf

Refactor EventComponent logic + add onOwnershipChange callback (#15354)

Dominic Gannaway committed Apr 9, 2019 at 12:47 UTC aece8119cf82a6eff02d9ad819758b7ac2c9b329
13 files changed +229 -117
packages/react-art/src/ReactARTHostConfig.js
+10 -6
@@ -11,6 +11,7 @@ import * as Scheduler from 'scheduler';
11 import invariant from 'shared/invariant';
12
13 import {TYPES, EVENT_TYPES, childrenAsString} from './ReactARTInternals';
14 +import type {ReactEventComponentInstance} from 'shared/ReactTypes';
15
16 // Intentionally not named imports because Rollup would
17 // use dynamic dispatch for CommonJS interop named imports.
@@ -439,17 +440,20 @@ export function unhideTextInstance(textInstance, text): void {
440 // Noop
441 }
442
442 -export function handleEventComponent(
443 - eventResponder: ReactEventResponder,
444 - rootContainerInstance: Container,
443 +export function mountEventComponent(
444 + eventComponentInstance: ReactEventComponentInstance,
445 +) {
446 + throw new Error('Not yet implemented.');
447 +}
448 +
449 +export function updateEventComponent(
450 + eventComponentInstance: ReactEventComponentInstance,
451 ) {
452 throw new Error('Not yet implemented.');
453 }
454
455 export function unmountEventComponent(
450 - eventResponder: ReactEventResponder,
451 - rootContainerInstance: Container,
452 - internalInstanceHandle: Object,
456 + eventComponentInstance: ReactEventComponentInstance,
457 ): void {
458 throw new Error('Not yet implemented.');
459 }
packages/react-dom/src/client/ReactDOMHostConfig.js
+20 -10
@@ -44,8 +44,11 @@ import {
44 import dangerousStyleValue from '../shared/dangerousStyleValue';
45
46 import type {DOMContainer} from './ReactDOM';
47 -import type {ReactEventResponder} from 'shared/ReactTypes';
48 -import {unmountEventResponder} from '../events/DOMEventResponderSystem';
47 +import type {ReactEventComponentInstance} from 'shared/ReactTypes';
48 +import {
49 + mountEventResponder,
50 + unmountEventResponder,
51 +} from '../events/DOMEventResponderSystem';
52 import {REACT_EVENT_TARGET_TOUCH_HIT} from 'shared/ReactSymbols';
53 import {canUseDOM} from 'shared/ExecutionEnvironment';
54
@@ -888,27 +891,34 @@ export function didNotFindHydratableSuspenseInstance(
891 }
892 }
893
891 -export function handleEventComponent(
892 - eventResponder: ReactEventResponder,
893 - rootContainerInstance: Container,
894 +export function mountEventComponent(
895 + eventComponentInstance: ReactEventComponentInstance,
896 ): void {
897 if (enableEventAPI) {
898 + mountEventResponder(eventComponentInstance);
899 + updateEventComponent(eventComponentInstance);
900 + }
901 +}
902 +
903 +export function updateEventComponent(
904 + eventComponentInstance: ReactEventComponentInstance,
905 +): void {
906 + if (enableEventAPI) {
907 + const rootContainerInstance = ((eventComponentInstance.rootInstance: any): Container);
908 const rootElement = rootContainerInstance.ownerDocument;
909 listenToEventResponderEventTypes(
898 - eventResponder.targetEventTypes,
910 + eventComponentInstance.responder.targetEventTypes,
911 rootElement,
912 );
913 }
914 }
915
916 export function unmountEventComponent(
905 - eventResponder: ReactEventResponder,
906 - rootContainerInstance: Container,
907 - internalInstanceHandle: Object,
917 + eventComponentInstance: ReactEventComponentInstance,
918 ): void {
919 if (enableEventAPI) {
920 // TODO stop listening to targetEventTypes
911 - unmountEventResponder(eventResponder, internalInstanceHandle);
921 + unmountEventResponder(eventComponentInstance);
922 }
923 }
924
packages/react-dom/src/events/DOMEventResponderSystem.js
+76 -45
@@ -22,8 +22,8 @@ import {
22 EventTarget as EventTargetWorkTag,
23 } from 'shared/ReactWorkTags';
24 import type {
25 - ReactEventResponder,
25 ReactEventResponderEventType,
26 + ReactEventComponentInstance,
27 } from 'shared/ReactTypes';
28 import type {DOMTopLevelEventType} from 'events/TopLevelEventTypes';
29 import {batchedUpdates, interactiveUpdates} from 'events/ReactGenericBatching';
@@ -55,7 +55,7 @@ type PartialEventObject = {
55 };
56
57 let currentOwner = null;
58 -let currentFiber: Fiber;
58 +let currentInstance: ReactEventComponentInstance;
59 let currentEventQueue: EventQueue;
60
61 const eventResponderContext: ResponderContext = {
@@ -140,12 +140,10 @@ const eventResponderContext: ResponderContext = {
140 return false;
141 },
142 isTargetWithinEventComponent(target: Element | Document): boolean {
143 - const eventFiber = currentFiber;
144 -
143 if (target != null) {
144 let fiber = getClosestInstanceFromNode(target);
145 while (fiber !== null) {
148 - if (fiber === eventFiber || fiber === eventFiber.alternate) {
146 + if (fiber.stateNode === currentInstance) {
147 return true;
148 }
149 fiber = fiber.return;
@@ -174,78 +172,78 @@ const eventResponderContext: ResponderContext = {
172 rootEventTypes: Array<ReactEventResponderEventType>,
173 ): void {
174 listenToResponderEventTypesImpl(rootEventTypes, doc);
177 - const eventComponent = currentFiber;
175 for (let i = 0; i < rootEventTypes.length; i++) {
176 const rootEventType = rootEventTypes[i];
177 const topLevelEventType =
178 typeof rootEventType === 'string' ? rootEventType : rootEventType.name;
182 - let rootEventComponents = rootEventTypesToEventComponents.get(
179 + let rootEventComponentInstances = rootEventTypesToEventComponentInstances.get(
180 topLevelEventType,
181 );
185 - if (rootEventComponents === undefined) {
186 - rootEventComponents = new Set();
187 - rootEventTypesToEventComponents.set(
182 + if (rootEventComponentInstances === undefined) {
183 + rootEventComponentInstances = new Set();
184 + rootEventTypesToEventComponentInstances.set(
185 topLevelEventType,
189 - rootEventComponents,
186 + rootEventComponentInstances,
187 );
188 }
192 - rootEventComponents.add(eventComponent);
189 + rootEventComponentInstances.add(currentInstance);
190 }
191 },
192 removeRootEventTypes(
193 rootEventTypes: Array<ReactEventResponderEventType>,
194 ): void {
198 - const eventComponent = currentFiber;
195 for (let i = 0; i < rootEventTypes.length; i++) {
196 const rootEventType = rootEventTypes[i];
197 const topLevelEventType =
198 typeof rootEventType === 'string' ? rootEventType : rootEventType.name;
203 - let rootEventComponents = rootEventTypesToEventComponents.get(
199 + let rootEventComponents = rootEventTypesToEventComponentInstances.get(
200 topLevelEventType,
201 );
202 if (rootEventComponents !== undefined) {
207 - rootEventComponents.delete(eventComponent);
203 + rootEventComponents.delete(currentInstance);
204 }
205 }
206 },
207 hasOwnership(): boolean {
212 - return currentOwner === currentFiber;
208 + return currentOwner === currentInstance;
209 },
210 requestOwnership(): boolean {
211 if (currentOwner !== null) {
212 return false;
213 }
218 - currentOwner = currentFiber;
214 + currentOwner = currentInstance;
215 + triggerOwnershipListeners();
216 return true;
217 },
218 releaseOwnership(): boolean {
222 - if (currentOwner !== currentFiber) {
219 + if (currentOwner !== currentInstance) {
220 return false;
221 }
222 currentOwner = null;
223 + triggerOwnershipListeners();
224 return false;
225 },
226 setTimeout(func: () => void, delay): TimeoutID {
229 - const contextFiber = currentFiber;
227 + const contextInstance = currentInstance;
228 return setTimeout(() => {
229 const previousEventQueue = currentEventQueue;
232 - const previousFiber = currentFiber;
230 + const previousInstance = currentInstance;
231 currentEventQueue = createEventQueue();
234 - currentFiber = contextFiber;
232 + currentInstance = contextInstance;
233 try {
234 func();
235 batchedUpdates(processEventQueue, currentEventQueue);
236 } finally {
239 - currentFiber = previousFiber;
237 + currentInstance = previousInstance;
238 currentEventQueue = previousEventQueue;
239 }
240 }, delay);
241 },
242 };
243
246 -const rootEventTypesToEventComponents: Map<
244 +const rootEventTypesToEventComponentInstances: Map<
245 DOMTopLevelEventType | string,
248 - Set<Fiber>,
246 + Set<ReactEventComponentInstance>,
247 > = new Map();
248 const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set;
249 const eventsWithStopPropagation:
@@ -255,6 +253,7 @@ const targetEventTypeCached: Map<
253 Array<ReactEventResponderEventType>,
254 Set<DOMTopLevelEventType>,
255 > = new Map();
256 +const ownershipChangeListeners: Set<ReactEventComponentInstance> = new Set();
257
258 function createResponderEvent(
259 topLevelType: string,
@@ -343,11 +342,11 @@ function getTargetEventTypes(
342
343 function handleTopLevelType(
344 topLevelType: DOMTopLevelEventType,
346 - fiber: Fiber,
345 responderEvent: ResponderEvent,
346 + eventComponentInstance: ReactEventComponentInstance,
347 isRootLevelEvent: boolean,
348 ): void {
350 - const responder: ReactEventResponder = fiber.type.responder;
349 + let {props, responder, state} = eventComponentInstance;
350 if (!isRootLevelEvent) {
351 // Validate the target event type exists on the responder
352 const targetEventTypes = getTargetEventTypes(responder.targetEventTypes);
@@ -355,13 +354,12 @@ function handleTopLevelType(
354 return;
355 }
356 }
358 - let {props, state} = fiber.stateNode;
359 - const previousFiber = currentFiber;
360 - currentFiber = fiber;
357 + const previousInstance = currentInstance;
358 + currentInstance = eventComponentInstance;
359 try {
360 responder.onEvent(responderEvent, eventResponderContext, props, state);
361 } finally {
364 - currentFiber = previousFiber;
362 + currentInstance = previousInstance;
363 }
364 }
365
@@ -384,23 +382,29 @@ export function runResponderEventsInBatch(
382 // Traverse up the fiber tree till we find event component fibers.
383 while (node !== null) {
384 if (node.tag === EventComponent) {
387 - handleTopLevelType(topLevelType, node, responderEvent, false);
385 + const eventComponentInstance = node.stateNode;
386 + handleTopLevelType(
387 + topLevelType,
388 + responderEvent,
389 + eventComponentInstance,
390 + false,
391 + );
392 }
393 node = node.return;
394 }
395 // Handle root level events
392 - const rootEventComponents = rootEventTypesToEventComponents.get(
396 + const rootEventInstances = rootEventTypesToEventComponentInstances.get(
397 topLevelType,
398 );
395 - if (rootEventComponents !== undefined) {
396 - const rootEventComponentFibers = Array.from(rootEventComponents);
399 + if (rootEventInstances !== undefined) {
400 + const rootEventComponentInstances = Array.from(rootEventInstances);
401
398 - for (let i = 0; i < rootEventComponentFibers.length; i++) {
399 - const rootEventComponentFiber = rootEventComponentFibers[i];
402 + for (let i = 0; i < rootEventComponentInstances.length; i++) {
403 + const rootEventComponentInstance = rootEventComponentInstances[i];
404 handleTopLevelType(
405 topLevelType,
402 - rootEventComponentFiber,
406 responderEvent,
407 + rootEventComponentInstance,
408 true,
409 );
410 }
@@ -409,26 +413,53 @@ export function runResponderEventsInBatch(
413 }
414 }
415
416 +function triggerOwnershipListeners(): void {
417 + const listeningInstances = Array.from(ownershipChangeListeners);
418 + const previousInstance = currentInstance;
419 + for (let i = 0; i < listeningInstances.length; i++) {
420 + const instance = listeningInstances[i];
421 + const {props, responder, state} = instance;
422 + currentInstance = instance;
423 + try {
424 + responder.onOwnershipChange(eventResponderContext, props, state);
425 + } finally {
426 + currentInstance = previousInstance;
427 + }
428 + }
429 +}
430 +
431 +export function mountEventResponder(
432 + eventComponentInstance: ReactEventComponentInstance,
433 +) {
434 + const responder = eventComponentInstance.responder;
435 + if (responder.onOwnershipChange !== undefined) {
436 + ownershipChangeListeners.add(eventComponentInstance);
437 + }
438 +}
439 +
440 export function unmountEventResponder(
413 - responder: ReactEventResponder,
414 - fiber: Fiber,
441 + eventComponentInstance: ReactEventComponentInstance,
442 ): void {
443 + const responder = eventComponentInstance.responder;
444 const onUnmount = responder.onUnmount;
445 if (onUnmount !== undefined) {
418 - let {props, state} = fiber.stateNode;
446 + let {props, state} = eventComponentInstance;
447 const previousEventQueue = currentEventQueue;
420 - const previousFiber = currentFiber;
448 + const previousInstance = currentInstance;
449 currentEventQueue = createEventQueue();
422 - currentFiber = fiber;
450 + currentInstance = eventComponentInstance;
451 try {
452 onUnmount(eventResponderContext, props, state);
453 } finally {
454 currentEventQueue = previousEventQueue;
427 - currentFiber = previousFiber;
455 + currentInstance = previousInstance;
456 }
457 }
430 - if (currentOwner === fiber) {
431 - // TODO fire owner changed callback
458 + if (currentOwner === eventComponentInstance) {
459 currentOwner = null;
460 + triggerOwnershipListeners();
461 + }
462 + if (responder.onOwnershipChange !== undefined) {
463 + ownershipChangeListeners.delete(eventComponentInstance);
464 }
465 }
packages/react-dom/src/events/__tests__/DOMEventResponderSystem-test.internal.js
+36
@@ -18,12 +18,14 @@ function createReactEventComponent(
18 createInitialState,
19 onEvent,
20 onUnmount,
21 + onOwnershipChange,
22 ) {
23 const testEventResponder = {
24 targetEventTypes,
25 createInitialState,
26 onEvent,
27 onUnmount,
28 + onOwnershipChange,
29 };
30
31 return {
@@ -378,4 +380,38 @@ describe('DOMEventResponderSystem', () => {
380 ReactDOM.render(null, container);
381 expect(counter).toEqual(5);
382 });
383 +
384 + it('the event responder onOwnershipChange() function should fire', () => {
385 + let onOwnershipChangeFired = 0;
386 + let ownershipGained = false;
387 + const buttonRef = React.createRef();
388 +
389 + const EventComponent = createReactEventComponent(
390 + ['click'],
391 + undefined,
392 + (event, context, props, state) => {
393 + ownershipGained = context.requestOwnership();
394 + },
395 + undefined,
396 + () => {
397 + onOwnershipChangeFired++;
398 + },
399 + );
400 +
401 + const Test = () => (
402 + <EventComponent>
403 + <button ref={buttonRef} />
404 + </EventComponent>
405 + );
406 +
407 + ReactDOM.render(<Test />, container);
408 +
409 + // Clicking the button should trigger the event responder onEvent()
410 + let buttonElement = buttonRef.current;
411 + dispatchClickEvent(buttonElement);
412 + jest.runAllTimers();
413 +
414 + expect(ownershipGained).toEqual(true);
415 + expect(onOwnershipChangeFired).toEqual(1);
416 + });
417 });
packages/react-native-renderer/src/ReactFabricHostConfig.js
+10 -7
@@ -14,7 +14,7 @@ import type {
14 NativeMethodsMixinType,
15 ReactNativeBaseComponentViewConfig,
16 } from './ReactNativeTypes';
17 -import type {ReactEventResponder} from 'shared/ReactTypes';
17 +import type {ReactEventComponentInstance} from 'shared/ReactTypes';
18
19 import {mountSafeCallback_NOT_REALLY_SAFE} from './NativeMethodsMixinUtils';
20 import {create, diff} from './ReactNativeAttributePayload';
@@ -434,17 +434,20 @@ export function replaceContainerChildren(
434 newChildren: ChildSet,
435 ): void {}
436
437 -export function handleEventComponent(
438 - eventResponder: ReactEventResponder,
439 - rootContainerInstance: Container,
437 +export function mountEventComponent(
438 + eventComponentInstance: ReactEventComponentInstance,
439 +) {
440 + throw new Error('Not yet implemented.');
441 +}
442 +
443 +export function updateEventComponent(
444 + eventComponentInstance: ReactEventComponentInstance,
445 ) {
446 throw new Error('Not yet implemented.');
447 }
448
449 export function unmountEventComponent(
445 - eventResponder: ReactEventResponder,
446 - rootContainerInstance: Container,
447 - internalInstanceHandle: Object,
450 + eventComponentInstance: ReactEventComponentInstance,
451 ): void {
452 throw new Error('Not yet implemented.');
453 }
packages/react-native-renderer/src/ReactNativeHostConfig.js
+10 -7
@@ -8,7 +8,7 @@
8 */
9
10 import type {ReactNativeBaseComponentViewConfig} from './ReactNativeTypes';
11 -import type {ReactEventResponder} from 'shared/ReactTypes';
11 +import type {ReactEventComponentInstance} from 'shared/ReactTypes';
12
13 import invariant from 'shared/invariant';
14
@@ -493,17 +493,20 @@ export function unhideTextInstance(
493 throw new Error('Not yet implemented.');
494 }
495
496 -export function handleEventComponent(
497 - eventResponder: ReactEventResponder,
498 - rootContainerInstance: Container,
496 +export function mountEventComponent(
497 + eventComponentInstance: ReactEventComponentInstance,
498 +) {
499 + throw new Error('Not yet implemented.');
500 +}
501 +
502 +export function updateEventComponent(
503 + eventComponentInstance: ReactEventComponentInstance,
504 ) {
505 throw new Error('Not yet implemented.');
506 }
507
508 export function unmountEventComponent(
504 - eventResponder: ReactEventResponder,
505 - rootContainerInstance: Container,
506 - internalInstanceHandle: Object,
509 + eventComponentInstance: ReactEventComponentInstance,
510 ): void {
511 throw new Error('Not yet implemented.');
512 }
packages/react-noop-renderer/src/createReactNoop.js
+5 -1
@@ -431,7 +431,11 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
431 isPrimaryRenderer: true,
432 supportsHydration: false,
433
434 - handleEventComponent(): void {
434 + mountEventComponent(): void {
435 + // NO-OP
436 + },
437 +
438 + updateEventComponent(): void {
439 // NO-OP
440 },
441
packages/react-reconciler/src/ReactFiber.js
-6
@@ -623,12 +623,6 @@ export function createFiberFromEventComponent(
623 const fiber = createFiber(EventComponent, pendingProps, key, mode);
624 fiber.elementType = eventComponent;
625 fiber.type = eventComponent;
626 - fiber.stateNode = {
627 - context: null,
628 - props: pendingProps,
629 - rootInstance: null,
630 - state: null,
631 - };
626 fiber.expirationTime = expirationTime;
627 return fiber;
628 }
packages/react-reconciler/src/ReactFiberCommitWork.js
+2 -3
@@ -749,9 +749,8 @@ function commitUnmount(current: Fiber): void {
749 }
750 case EventComponent: {
751 if (enableEventAPI) {
752 - const rootContainerInstance = current.stateNode.rootInstance;
753 - const responder = current.type.responder;
754 - unmountEventComponent(responder, rootContainerInstance, current);
752 + const eventComponentInstance = current.stateNode;
753 + unmountEventComponent(eventComponentInstance);
754 current.stateNode = null;
755 }
756 }
packages/react-reconciler/src/ReactFiberCompleteWork.js
+25 -13
@@ -17,6 +17,7 @@ import type {
17 Container,
18 ChildSet,
19 } from './ReactFiberHostConfig';
20 +import type {ReactEventComponentInstance} from 'shared/ReactTypes';
21
22 import {
23 IndeterminateComponent,
@@ -65,7 +66,8 @@ import {
66 createContainerChildSet,
67 appendChildToContainerChildSet,
68 finalizeContainerChildren,
68 - handleEventComponent,
69 + mountEventComponent,
70 + updateEventComponent,
71 handleEventTarget,
72 } from './ReactFiberHostConfig';
73 import {
@@ -774,19 +776,29 @@ function completeWork(
776 popHostContext(workInProgress);
777 const rootContainerInstance = getRootHostContainer();
778 const responder = workInProgress.type.responder;
777 - const stateNode = workInProgress.stateNode;
778 - // Update the props on the event component state node
779 - stateNode.props = newProps;
780 - // Update the root container, so we can properly unmount events at some point
781 - stateNode.rootInstance = rootContainerInstance;
782 - // Initialize event component state if createInitialState exists
783 - if (
784 - stateNode.state === null &&
785 - responder.createInitialState !== undefined
786 - ) {
787 - stateNode.state = responder.createInitialState(newProps);
779 + let eventComponentInstance: ReactEventComponentInstance | null =
780 + workInProgress.stateNode;
781 +
782 + if (eventComponentInstance === null) {
783 + let responderState = null;
784 + if (responder.createInitialState !== undefined) {
785 + responderState = responder.createInitialState(newProps);
786 + }
787 + eventComponentInstance = workInProgress.stateNode = {
788 + context: null,
789 + props: newProps,
790 + responder,
791 + rootInstance: rootContainerInstance,
792 + state: responderState,
793 + };
794 + mountEventComponent(eventComponentInstance);
795 + } else {
796 + // Update the props on the event component state node
797 + eventComponentInstance.props = newProps;
798 + // Update the root container, so we can properly unmount events at some point
799 + eventComponentInstance.rootInstance = rootContainerInstance;
800 + updateEventComponent(eventComponentInstance);
801 }
789 - handleEventComponent(responder, rootContainerInstance);
802 }
803 break;
804 }
packages/react-reconciler/src/forks/ReactFiberHostConfig.custom.js
+2 -1
@@ -63,7 +63,8 @@ export const isPrimaryRenderer = $$$hostConfig.isPrimaryRenderer;
63 export const supportsMutation = $$$hostConfig.supportsMutation;
64 export const supportsPersistence = $$$hostConfig.supportsPersistence;
65 export const supportsHydration = $$$hostConfig.supportsHydration;
66 -export const handleEventComponent = $$$hostConfig.handleEventComponent;
66 +export const mountEventComponent = $$$hostConfig.mountEventComponent;
67 +export const updateEventComponent = $$$hostConfig.updateEventComponent;
68 export const handleEventTarget = $$$hostConfig.handleEventTarget;
69 export const getEventTargetChildElement =
70 $$$hostConfig.getEventTargetChildElement;
packages/react-test-renderer/src/ReactTestHostConfig.js
+15 -12
@@ -9,7 +9,7 @@
9
10 import warning from 'shared/warning';
11
12 -import type {ReactEventResponder} from 'shared/ReactTypes';
12 +import type {ReactEventComponentInstance} from 'shared/ReactTypes';
13 import {REACT_EVENT_TARGET_TOUCH_HIT} from 'shared/ReactSymbols';
14
15 import {enableEventAPI} from 'shared/ReactFeatureFlags';
@@ -327,9 +327,20 @@ export function unhideTextInstance(
327 textInstance.isHidden = false;
328 }
329
330 -export function handleEventComponent(
331 - eventResponder: ReactEventResponder,
332 - rootContainerInstance: Container,
330 +export function mountEventComponent(
331 + eventComponentInstance: ReactEventComponentInstance,
332 +): void {
333 + // noop
334 +}
335 +
336 +export function updateEventComponent(
337 + eventComponentInstance: ReactEventComponentInstance,
338 +): void {
339 + // noop
340 +}
341 +
342 +export function unmountEventComponent(
343 + eventComponentInstance: ReactEventComponentInstance,
344 ): void {
345 // noop
346 }
@@ -363,14 +374,6 @@ export function getEventTargetChildElement(
374 return null;
375 }
376
366 -export function unmountEventComponent(
367 - eventResponder: ReactEventResponder,
368 - rootContainerInstance: Container,
369 - internalInstanceHandle: Object,
370 -): void {
371 - // TODO: add unmountEventComponent implementation
372 -}
373 -
377 export function handleEventTarget(
378 type: Symbol | number,
379 props: Props,
packages/shared/ReactTypes.js
+18 -6
@@ -89,21 +89,33 @@ export type ReactEventResponderEventType =
89
90 export type ReactEventResponder = {
91 targetEventTypes: Array<ReactEventResponderEventType>,
92 - createInitialState?: (props: Object) => Object,
92 + createInitialState?: (props: null | Object) => Object,
93 onEvent: (
94 event: ResponderEvent,
95 context: ResponderContext,
96 - props: Object,
97 - state: Object,
96 + props: null | Object,
97 + state: null | Object,
98 + ) => void,
99 + onUnmount: (
100 + context: ResponderContext,
101 + props: null | Object,
102 + state: null | Object,
103 ) => void,
99 - onUnmount: (context: ResponderContext, props: Object, state: Object) => void,
104 onOwnershipChange: (
105 context: ResponderContext,
102 - props: Object,
103 - state: Object,
106 + props: null | Object,
107 + state: null | Object,
108 ) => void,
109 };
110
111 +export type ReactEventComponentInstance = {|
112 + context: null | Object,
113 + props: null | Object,
114 + responder: ReactEventResponder,
115 + rootInstance: mixed,
116 + state: null | Object,
117 +|};
118 +
119 export type ReactEventComponent = {|
120 $$typeof: Symbol | number,
121 displayName?: string,