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,