Move EventComponent state creation to complete phase + tests (#15352)
Dominic Gannaway committed
Apr 8, 2019 at 16:02 UTC
29fb5862fb5f7896331d53c631b77a0c0e03a7c2
3 files changed
+51
-19
packages/react-dom/src/events/DOMEventResponderSystem.js
-15
@@ -56,7 +56,6 @@ type PartialEventObject = {
56
57
let currentOwner = null;
58
let currentFiber: Fiber;
59
-let currentResponder: ReactEventResponder;
59
let currentEventQueue: EventQueue;
60
61
const eventResponderContext: ResponderContext = {
@@ -227,14 +226,11 @@ const eventResponderContext: ResponderContext = {
226
return false;
227
},
228
setTimeout(func: () => void, delay): TimeoutID {
230
- const contextResponder = currentResponder;
229
const contextFiber = currentFiber;
230
return setTimeout(() => {
231
const previousEventQueue = currentEventQueue;
232
const previousFiber = currentFiber;
235
- const previousResponder = currentResponder;
233
currentEventQueue = createEventQueue();
237
- currentResponder = contextResponder;
234
currentFiber = contextFiber;
235
try {
236
func();
@@ -242,7 +238,6 @@ const eventResponderContext: ResponderContext = {
238
} finally {
239
currentFiber = previousFiber;
240
currentEventQueue = previousEventQueue;
245
- currentResponder = previousResponder;
241
}
242
}, delay);
243
},
@@ -361,19 +356,12 @@ function handleTopLevelType(
356
}
357
}
358
let {props, state} = fiber.stateNode;
364
- if (state === null && responder.createInitialState !== undefined) {
365
- state = fiber.stateNode.state = responder.createInitialState(props);
366
- }
359
const previousFiber = currentFiber;
368
- const previousResponder = currentResponder;
360
currentFiber = fiber;
370
- currentResponder = responder;
371
-
361
try {
362
responder.onEvent(responderEvent, eventResponderContext, props, state);
363
} finally {
364
currentFiber = previousFiber;
376
- currentResponder = previousResponder;
365
}
366
}
367
@@ -430,16 +418,13 @@ export function unmountEventResponder(
418
let {props, state} = fiber.stateNode;
419
const previousEventQueue = currentEventQueue;
420
const previousFiber = currentFiber;
433
- const previousResponder = currentResponder;
421
currentEventQueue = createEventQueue();
422
currentFiber = fiber;
436
- currentResponder = responder;
423
try {
424
onUnmount(eventResponderContext, props, state);
425
} finally {
426
currentEventQueue = previousEventQueue;
427
currentFiber = previousFiber;
442
- currentResponder = previousResponder;
428
}
429
}
430
if (currentOwner === fiber) {
packages/react-dom/src/events/__tests__/DOMEventResponderSystem-test.internal.js
+41
-2
@@ -13,9 +13,15 @@ let React;
13
let ReactFeatureFlags;
14
let ReactDOM;
15
16
-function createReactEventComponent(targetEventTypes, onEvent, onUnmount) {
16
+function createReactEventComponent(
17
+ targetEventTypes,
18
+ createInitialState,
19
+ onEvent,
20
+ onUnmount,
21
+) {
22
const testEventResponder = {
23
targetEventTypes,
24
+ createInitialState,
25
onEvent,
26
onUnmount,
27
};
@@ -61,6 +67,7 @@ describe('DOMEventResponderSystem', () => {
67
68
const ClickEventComponent = createReactEventComponent(
69
['click'],
70
+ undefined,
71
(event, context, props) => {
72
eventResponderFiredCount++;
73
eventLog.push({
@@ -114,6 +121,7 @@ describe('DOMEventResponderSystem', () => {
121
122
const ClickEventComponent = createReactEventComponent(
123
['click'],
124
+ undefined,
125
(event, context, props) => {
126
eventLog.push({
127
name: event.type,
@@ -149,6 +157,7 @@ describe('DOMEventResponderSystem', () => {
157
158
const ClickEventComponent = createReactEventComponent(
159
['click'],
160
+ undefined,
161
(event, context, props) => {
162
eventResponderFiredCount++;
163
eventLog.push({
@@ -193,6 +202,7 @@ describe('DOMEventResponderSystem', () => {
202
203
const ClickEventComponentA = createReactEventComponent(
204
['click'],
205
+ undefined,
206
(context, props) => {
207
eventLog.push('A');
208
},
@@ -200,6 +210,7 @@ describe('DOMEventResponderSystem', () => {
210
211
const ClickEventComponentB = createReactEventComponent(
212
['click'],
213
+ undefined,
214
(context, props) => {
215
eventLog.push('B');
216
},
@@ -228,6 +239,7 @@ describe('DOMEventResponderSystem', () => {
239
240
const ClickEventComponent = createReactEventComponent(
241
['click'],
242
+ undefined,
243
(event, context, props) => {
244
if (props.onMagicClick) {
245
const syntheticEvent = {
@@ -265,6 +277,7 @@ describe('DOMEventResponderSystem', () => {
277
278
const LongPressEventComponent = createReactEventComponent(
279
['click'],
280
+ undefined,
281
(event, context, props) => {
282
const pressEvent = {
283
listener: props.onPress,
@@ -323,7 +336,8 @@ describe('DOMEventResponderSystem', () => {
336
337
const EventComponent = createReactEventComponent(
338
[],
326
- (event, context, props) => {},
339
+ undefined,
340
+ (event, context, props, state) => {},
341
() => {
342
onUnmountFired++;
343
},
@@ -339,4 +353,29 @@ describe('DOMEventResponderSystem', () => {
353
ReactDOM.render(null, container);
354
expect(onUnmountFired).toEqual(1);
355
});
356
+
357
+ it('the event responder onUnmount() function should fire with state', () => {
358
+ let counter = 0;
359
+
360
+ const EventComponent = createReactEventComponent(
361
+ [],
362
+ () => ({
363
+ incrementAmount: 5,
364
+ }),
365
+ (event, context, props, state) => {},
366
+ (context, props, state) => {
367
+ counter += state.incrementAmount;
368
+ },
369
+ );
370
+
371
+ const Test = () => (
372
+ <EventComponent>
373
+ <button />
374
+ </EventComponent>
375
+ );
376
+
377
+ ReactDOM.render(<Test />, container);
378
+ ReactDOM.render(null, container);
379
+ expect(counter).toEqual(5);
380
+ });
381
});
packages/react-reconciler/src/ReactFiberCompleteWork.js
+10
-2
@@ -774,10 +774,18 @@ function completeWork(
774
popHostContext(workInProgress);
775
const rootContainerInstance = getRootHostContainer();
776
const responder = workInProgress.type.responder;
777
+ const stateNode = workInProgress.stateNode;
778
// Update the props on the event component state node
778
- workInProgress.stateNode.props = newProps;
779
+ stateNode.props = newProps;
780
// Update the root container, so we can properly unmount events at some point
780
- workInProgress.stateNode.rootInstance = rootContainerInstance;
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);
788
+ }
789
handleEventComponent(responder, rootContainerInstance);
790
}
791
break;