[react-events] Ensure updateEventListeners updates in commit phase (#16540)
Dominic Gannaway committed
Aug 22, 2019 at 23:58 UTC
fc807720780962729df2ad1b0f53258603c020c7
10 files changed
+261
-249
packages/react-art/src/ReactARTHostConfig.js
-1
@@ -432,7 +432,6 @@ export function mountResponderInstance(
432
props: Object,
433
state: Object,
434
instance: Object,
435
- rootContainerInstance: Object,
435
) {
436
throw new Error('Not yet implemented.');
437
}
packages/react-dom/src/client/ReactDOMHostConfig.js
+1
-2
@@ -824,10 +824,9 @@ export function mountResponderInstance(
824
responderProps: Object,
825
responderState: Object,
826
instance: Instance,
827
- rootContainerInstance: Container,
827
): ReactDOMEventResponderInstance {
828
// Listen to events
830
- const doc = rootContainerInstance.ownerDocument;
829
+ const doc = instance.ownerDocument;
830
const documentBody = doc.body || doc;
831
const {
832
rootEventTypes,
packages/react-dom/src/events/DOMEventResponderSystem.js
+9
-5
@@ -12,7 +12,7 @@ import {
12
PASSIVE_NOT_SUPPORTED,
13
} from 'legacy-events/EventSystemFlags';
14
import type {AnyNativeEvent} from 'legacy-events/PluginModuleType';
15
-import {HostComponent} from 'shared/ReactWorkTags';
15
+import {HostComponent, SuspenseComponent} from 'shared/ReactWorkTags';
16
import type {EventPriority} from 'shared/ReactTypes';
17
import type {
18
ReactDOMEventResponder,
@@ -32,10 +32,6 @@ import type {Fiber} from 'react-reconciler/src/ReactFiber';
32
import warning from 'shared/warning';
33
import {enableFlareAPI} from 'shared/ReactFeatureFlags';
34
import invariant from 'shared/invariant';
35
-import {
36
- isFiberSuspenseAndTimedOut,
37
- getSuspenseFallbackChild,
38
-} from 'react-reconciler/src/ReactFiberEvents';
35
36
import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
37
import {
@@ -630,6 +626,14 @@ function validateResponderContext(): void {
626
);
627
}
628
629
+function isFiberSuspenseAndTimedOut(fiber: Fiber): boolean {
630
+ return fiber.tag === SuspenseComponent && fiber.memoizedState !== null;
631
+}
632
+
633
+function getSuspenseFallbackChild(fiber: Fiber): Fiber | null {
634
+ return ((((fiber.child: any): Fiber).sibling: any): Fiber).child;
635
+}
636
+
637
export function dispatchEventForResponderEventSystem(
638
topLevelType: string,
639
targetFiber: null | Fiber,
packages/react-dom/src/events/__tests__/DOMEventResponderSystem-test.internal.js
+68
-8
@@ -14,6 +14,7 @@ let ReactFeatureFlags;
14
let ReactDOM;
15
let ReactDOMServer;
16
let ReactTestRenderer;
17
+let Scheduler;
18
19
// FIXME: What should the public API be for setting an event's priority? Right
20
// now it's an enum but is that what we want? Hard coding this for now.
@@ -72,6 +73,7 @@ describe('DOMEventResponderSystem', () => {
73
React = require('react');
74
ReactDOM = require('react-dom');
75
ReactDOMServer = require('react-dom/server');
76
+ Scheduler = require('scheduler');
77
container = document.createElement('div');
78
document.body.appendChild(container);
79
});
@@ -811,8 +813,8 @@ describe('DOMEventResponderSystem', () => {
813
814
it('the event responder system should warn on accessing invalid properties', () => {
815
const TestResponder = createEventResponder({
814
- rootEventTypes: ['click'],
815
- onRootEvent: (event, context, props) => {
816
+ targetEventTypes: ['click'],
817
+ onEvent: (event, context, props) => {
818
const syntheticEvent = {
819
target: event.target,
820
type: 'click',
@@ -823,19 +825,24 @@ describe('DOMEventResponderSystem', () => {
825
});
826
827
let handler;
828
+ let buttonRef = React.createRef();
829
const Test = () => {
830
const listener = React.unstable_useResponder(TestResponder, {
831
onClick: handler,
832
});
833
831
- return <button listeners={listener}>Click me!</button>;
834
+ return (
835
+ <button listeners={listener} ref={buttonRef}>
836
+ Click me!
837
+ </button>
838
+ );
839
};
840
expect(() => {
841
handler = event => {
842
event.preventDefault();
843
};
844
ReactDOM.render(<Test />, container);
838
- dispatchClickEvent(document.body);
845
+ dispatchClickEvent(buttonRef.current);
846
}).toWarnDev(
847
'Warning: preventDefault() is not available on event objects created from event responder modules ' +
848
'(React Flare).' +
@@ -847,7 +854,7 @@ describe('DOMEventResponderSystem', () => {
854
event.stopPropagation();
855
};
856
ReactDOM.render(<Test />, container);
850
- dispatchClickEvent(document.body);
857
+ dispatchClickEvent(buttonRef.current);
858
}).toWarnDev(
859
'Warning: stopPropagation() is not available on event objects created from event responder modules ' +
860
'(React Flare).' +
@@ -859,7 +866,7 @@ describe('DOMEventResponderSystem', () => {
866
event.isDefaultPrevented();
867
};
868
ReactDOM.render(<Test />, container);
862
- dispatchClickEvent(document.body);
869
+ dispatchClickEvent(buttonRef.current);
870
}).toWarnDev(
871
'Warning: isDefaultPrevented() is not available on event objects created from event responder modules ' +
872
'(React Flare).' +
@@ -871,7 +878,7 @@ describe('DOMEventResponderSystem', () => {
878
event.isPropagationStopped();
879
};
880
ReactDOM.render(<Test />, container);
874
- dispatchClickEvent(document.body);
881
+ dispatchClickEvent(buttonRef.current);
882
}).toWarnDev(
883
'Warning: isPropagationStopped() is not available on event objects created from event responder modules ' +
884
'(React Flare).' +
@@ -883,7 +890,7 @@ describe('DOMEventResponderSystem', () => {
890
return event.nativeEvent;
891
};
892
ReactDOM.render(<Test />, container);
886
- dispatchClickEvent(document.body);
893
+ dispatchClickEvent(buttonRef.current);
894
}).toWarnDev(
895
'Warning: nativeEvent is not available on event objects created from event responder modules ' +
896
'(React Flare).' +
@@ -934,4 +941,57 @@ describe('DOMEventResponderSystem', () => {
941
ReactDOM.render(<Test2 />, container);
942
buttonRef.current.dispatchEvent(createEvent('foobar'));
943
});
944
+
945
+ it('should work with concurrent mode updates', async () => {
946
+ const log = [];
947
+ const TestResponder = createEventResponder({
948
+ targetEventTypes: ['click'],
949
+ onEvent(event, context, props) {
950
+ log.push(props);
951
+ },
952
+ });
953
+ const ref = React.createRef();
954
+
955
+ function Test({counter}) {
956
+ const listener = React.unstable_useResponder(TestResponder, {counter});
957
+
958
+ return (
959
+ <button listeners={listener} ref={ref}>
960
+ Press me
961
+ </button>
962
+ );
963
+ }
964
+
965
+ let root = ReactDOM.unstable_createRoot(container);
966
+ let batch = root.createBatch();
967
+ batch.render(<Test counter={0} />);
968
+ Scheduler.unstable_flushAll();
969
+ jest.runAllTimers();
970
+ batch.commit();
971
+
972
+ // Click the button
973
+ dispatchClickEvent(ref.current);
974
+ expect(log).toEqual([{counter: 0}]);
975
+
976
+ // Clear log
977
+ log.length = 0;
978
+
979
+ // Increase counter
980
+ batch = root.createBatch();
981
+ batch.render(<Test counter={1} />);
982
+ Scheduler.unstable_flushAll();
983
+ jest.runAllTimers();
984
+
985
+ // Click the button again
986
+ dispatchClickEvent(ref.current);
987
+ expect(log).toEqual([{counter: 0}]);
988
+
989
+ // Clear log
990
+ log.length = 0;
991
+
992
+ // Commit
993
+ batch.commit();
994
+ dispatchClickEvent(ref.current);
995
+ expect(log).toEqual([{counter: 1}]);
996
+ });
997
});
packages/react-native-renderer/src/ReactFabricHostConfig.js
-1
@@ -449,7 +449,6 @@ export function mountResponderInstance(
449
props: Object,
450
state: Object,
451
instance: Instance,
452
- rootContainerInstance: Container,
452
) {
453
if (enableFlareAPI) {
454
const {rootEventTypes} = responder;
packages/react-native-renderer/src/ReactNativeHostConfig.js
-1
@@ -501,7 +501,6 @@ export function mountResponderInstance(
501
props: Object,
502
state: Object,
503
instance: Instance,
504
- rootContainerInstance: Container,
504
) {
505
throw new Error('Not yet implemented.');
506
}
packages/react-reconciler/src/ReactFiberCommitWork.js
+8
@@ -118,6 +118,7 @@ import {
118
} from './ReactHookEffectTags';
119
import {didWarnAboutReassigningProps} from './ReactFiberBeginWork';
120
import {runWithPriority, NormalPriority} from './SchedulerWithReactIntegration';
121
+import {updateEventListeners} from './ReactFiberEvents';
122
123
let didWarnAboutUndefinedSnapshotBeforeUpdate: Set<mixed> | null = null;
124
if (__DEV__) {
@@ -1331,6 +1332,13 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1332
finishedWork,
1333
);
1334
}
1335
+ if (enableFlareAPI) {
1336
+ const prevListeners = oldProps.listeners;
1337
+ const nextListeners = newProps.listeners;
1338
+ if (prevListeners !== nextListeners) {
1339
+ updateEventListeners(nextListeners, instance, finishedWork);
1340
+ }
1341
+ }
1342
}
1343
return;
1344
}
packages/react-reconciler/src/ReactFiberCompleteWork.js
+5
-186
@@ -9,12 +9,7 @@
9
10
import type {Fiber} from './ReactFiber';
11
import type {ExpirationTime} from './ReactFiberExpirationTime';
12
-import type {
13
- ReactEventResponder,
14
- ReactEventResponderInstance,
15
- ReactFundamentalComponentInstance,
16
- ReactEventResponderListener,
17
-} from 'shared/ReactTypes';
12
+import type {ReactFundamentalComponentInstance} from 'shared/ReactTypes';
13
import type {FiberRoot} from './ReactFiberRoot';
14
import type {
15
Instance,
@@ -31,7 +26,6 @@ import type {SuspenseContext} from './ReactFiberSuspenseContext';
26
27
import {now} from './SchedulerWithReactIntegration';
28
34
-import {REACT_RESPONDER_TYPE} from 'shared/ReactSymbols';
29
import {
30
IndeterminateComponent,
31
FunctionComponent,
@@ -78,8 +72,6 @@ import {
72
createContainerChildSet,
73
appendChildToContainerChildSet,
74
finalizeContainerChildren,
81
- mountResponderInstance,
82
- unmountResponderInstance,
75
getFundamentalComponentInstance,
76
mountFundamentalComponent,
77
cloneFundamentalInstance,
@@ -91,8 +83,6 @@ import {
83
getHostContext,
84
popHostContainer,
85
} from './ReactFiberHostContext';
94
-import {NoWork} from './ReactFiberExpirationTime';
95
-import {createResponderInstance} from './ReactFiberEvents';
86
import {
87
suspenseStackCursor,
88
InvisibleParentSuspenseContext,
@@ -132,10 +122,7 @@ import {
122
import {createFundamentalStateInstance} from './ReactFiberFundamental';
123
import {Never} from './ReactFiberExpirationTime';
124
import {resetChildFibers} from './ReactChildFiber';
135
-import warning from 'shared/warning';
136
-
137
-const emptyObject = {};
138
-const isArray = Array.isArray;
125
+import {updateEventListeners} from './ReactFiberEvents';
126
127
function markUpdate(workInProgress: Fiber) {
128
// Tag the fiber with an update effect. This turns a Placement into
@@ -689,14 +676,8 @@ function completeWork(
676
if (enableFlareAPI) {
677
const prevListeners = current.memoizedProps.listeners;
678
const nextListeners = newProps.listeners;
692
- const instance = workInProgress.stateNode;
679
if (prevListeners !== nextListeners) {
694
- updateEventListeners(
695
- nextListeners,
696
- instance,
697
- rootContainerInstance,
698
- workInProgress,
699
- );
680
+ markUpdate(workInProgress);
681
}
682
}
683
@@ -738,12 +719,7 @@ function completeWork(
719
const instance = workInProgress.stateNode;
720
const listeners = newProps.listeners;
721
if (listeners != null) {
741
- updateEventListeners(
742
- listeners,
743
- instance,
744
- rootContainerInstance,
745
- workInProgress,
746
- );
722
+ updateEventListeners(listeners, instance, workInProgress);
723
}
724
}
725
} else {
@@ -760,12 +736,7 @@ function completeWork(
736
if (enableFlareAPI) {
737
const listeners = newProps.listeners;
738
if (listeners != null) {
763
- updateEventListeners(
764
- listeners,
765
- instance,
766
- rootContainerInstance,
767
- workInProgress,
768
- );
739
+ updateEventListeners(listeners, instance, workInProgress);
740
}
741
}
742
@@ -1253,156 +1224,4 @@ function completeWork(
1224
return null;
1225
}
1226
1256
-function mountEventResponder(
1257
- responder: ReactEventResponder<any, any>,
1258
- responderProps: Object,
1259
- instance: Instance,
1260
- rootContainerInstance: Container,
1261
- fiber: Fiber,
1262
- respondersMap: Map<
1263
- ReactEventResponder<any, any>,
1264
- ReactEventResponderInstance<any, any>,
1265
- >,
1266
-) {
1267
- let responderState = emptyObject;
1268
- const getInitialState = responder.getInitialState;
1269
- if (getInitialState !== null) {
1270
- responderState = getInitialState(responderProps);
1271
- }
1272
- const responderInstance = createResponderInstance(
1273
- responder,
1274
- responderProps,
1275
- responderState,
1276
- instance,
1277
- fiber,
1278
- );
1279
- mountResponderInstance(
1280
- responder,
1281
- responderInstance,
1282
- responderProps,
1283
- responderState,
1284
- instance,
1285
- rootContainerInstance,
1286
- );
1287
- respondersMap.set(responder, responderInstance);
1288
-}
1289
-
1290
-function updateEventListener(
1291
- listener: ReactEventResponderListener<any, any>,
1292
- fiber: Fiber,
1293
- visistedResponders: Set<ReactEventResponder<any, any>>,
1294
- respondersMap: Map<
1295
- ReactEventResponder<any, any>,
1296
- ReactEventResponderInstance<any, any>,
1297
- >,
1298
- instance: Instance,
1299
- rootContainerInstance: Container,
1300
-): void {
1301
- let responder;
1302
- let props;
1303
-
1304
- if (listener) {
1305
- responder = listener.responder;
1306
- props = listener.props;
1307
- }
1308
- invariant(
1309
- responder && responder.$$typeof === REACT_RESPONDER_TYPE,
1310
- 'An invalid value was used as an event listener. Expect one or many event ' +
1311
- 'listeners created via React.unstable_useResponder().',
1312
- );
1313
- const listenerProps = ((props: any): Object);
1314
- if (visistedResponders.has(responder)) {
1315
- // show warning
1316
- if (__DEV__) {
1317
- warning(
1318
- false,
1319
- 'Duplicate event responder "%s" found in event listeners. ' +
1320
- 'Event listeners passed to elements cannot use the same event responder more than once.',
1321
- responder.displayName,
1322
- );
1323
- }
1324
- return;
1325
- }
1326
- visistedResponders.add(responder);
1327
- const responderInstance = respondersMap.get(responder);
1328
-
1329
- if (responderInstance === undefined) {
1330
- // Mount
1331
- mountEventResponder(
1332
- responder,
1333
- listenerProps,
1334
- instance,
1335
- rootContainerInstance,
1336
- fiber,
1337
- respondersMap,
1338
- );
1339
- } else {
1340
- // Update
1341
- responderInstance.props = listenerProps;
1342
- responderInstance.fiber = fiber;
1343
- }
1344
-}
1345
-
1346
-function updateEventListeners(
1347
- listeners: any,
1348
- instance: Instance,
1349
- rootContainerInstance: Container,
1350
- fiber: Fiber,
1351
-): void {
1352
- const visistedResponders = new Set();
1353
- let dependencies = fiber.dependencies;
1354
- if (listeners != null) {
1355
- if (dependencies === null) {
1356
- dependencies = fiber.dependencies = {
1357
- expirationTime: NoWork,
1358
- firstContext: null,
1359
- responders: new Map(),
1360
- };
1361
- }
1362
- let respondersMap = dependencies.responders;
1363
- if (respondersMap === null) {
1364
- respondersMap = new Map();
1365
- }
1366
- if (isArray(listeners)) {
1367
- for (let i = 0, length = listeners.length; i < length; i++) {
1368
- const listener = listeners[i];
1369
- updateEventListener(
1370
- listener,
1371
- fiber,
1372
- visistedResponders,
1373
- respondersMap,
1374
- instance,
1375
- rootContainerInstance,
1376
- );
1377
- }
1378
- } else {
1379
- updateEventListener(
1380
- listeners,
1381
- fiber,
1382
- visistedResponders,
1383
- respondersMap,
1384
- instance,
1385
- rootContainerInstance,
1386
- );
1387
- }
1388
- }
1389
- if (dependencies !== null) {
1390
- const respondersMap = dependencies.responders;
1391
- if (respondersMap !== null) {
1392
- // Unmount
1393
- const mountedResponders = Array.from(respondersMap.keys());
1394
- for (let i = 0, length = mountedResponders.length; i < length; i++) {
1395
- const mountedResponder = mountedResponders[i];
1396
- if (!visistedResponders.has(mountedResponder)) {
1397
- const responderInstance = ((respondersMap.get(
1398
- mountedResponder,
1399
- ): any): ReactEventResponderInstance<any, any>);
1400
- unmountResponderInstance(responderInstance);
1401
- respondersMap.delete(mountedResponder);
1402
- }
1403
- }
1404
- }
1405
- }
1406
-}
1407
-
1227
export {completeWork};
packages/react-reconciler/src/ReactFiberEvents.js
+170
-44
@@ -8,59 +8,26 @@
8
*/
9
10
import type {Fiber} from './ReactFiber';
11
+import type {Instance} from './ReactFiberHostConfig';
12
import type {
13
ReactEventResponder,
14
ReactEventResponderInstance,
15
ReactEventResponderListener,
16
} from 'shared/ReactTypes';
16
-import type {Instance} from './ReactFiberHostConfig';
17
18
-import {SuspenseComponent, Fragment} from 'shared/ReactWorkTags';
18
+import {
19
+ mountResponderInstance,
20
+ unmountResponderInstance,
21
+} from './ReactFiberHostConfig';
22
+import {NoWork} from './ReactFiberExpirationTime';
23
20
-export function createResponderListener(
21
- responder: ReactEventResponder<any, any>,
22
- props: Object,
23
-): ReactEventResponderListener<any, any> {
24
- const eventResponderListener = {
25
- responder,
26
- props,
27
- };
28
- if (__DEV__) {
29
- Object.freeze(eventResponderListener);
30
- }
31
- return eventResponderListener;
32
-}
24
+import warning from 'shared/warning';
25
+import {REACT_RESPONDER_TYPE} from 'shared/ReactSymbols';
26
34
-export function isFiberSuspenseAndTimedOut(fiber: Fiber): boolean {
35
- return fiber.tag === SuspenseComponent && fiber.memoizedState !== null;
36
-}
27
+import invariant from 'shared/invariant';
28
38
-export function getSuspenseFallbackChild(fiber: Fiber): Fiber | null {
39
- return ((((fiber.child: any): Fiber).sibling: any): Fiber).child;
40
-}
41
-
42
-export function isFiberSuspenseTimedOutChild(fiber: Fiber | null): boolean {
43
- if (fiber === null) {
44
- return false;
45
- }
46
- const parent = fiber.return;
47
- if (parent !== null && parent.tag === Fragment) {
48
- const grandParent = parent.return;
49
-
50
- if (
51
- grandParent !== null &&
52
- grandParent.tag === SuspenseComponent &&
53
- grandParent.stateNode !== null
54
- ) {
55
- return true;
56
- }
57
- }
58
- return false;
59
-}
60
-
61
-export function getSuspenseFiberFromTimedOutChild(fiber: Fiber): Fiber {
62
- return ((((fiber.return: any): Fiber).return: any): Fiber);
63
-}
29
+const emptyObject = {};
30
+const isArray = Array.isArray;
31
32
export function createResponderInstance(
33
responder: ReactEventResponder<any, any>,
@@ -78,3 +45,162 @@ export function createResponderInstance(
45
target,
46
};
47
}
48
+
49
+function mountEventResponder(
50
+ responder: ReactEventResponder<any, any>,
51
+ responderProps: Object,
52
+ instance: Instance,
53
+ fiber: Fiber,
54
+ respondersMap: Map<
55
+ ReactEventResponder<any, any>,
56
+ ReactEventResponderInstance<any, any>,
57
+ >,
58
+) {
59
+ let responderState = emptyObject;
60
+ const getInitialState = responder.getInitialState;
61
+ if (getInitialState !== null) {
62
+ responderState = getInitialState(responderProps);
63
+ }
64
+ const responderInstance = createResponderInstance(
65
+ responder,
66
+ responderProps,
67
+ responderState,
68
+ instance,
69
+ fiber,
70
+ );
71
+ mountResponderInstance(
72
+ responder,
73
+ responderInstance,
74
+ responderProps,
75
+ responderState,
76
+ instance,
77
+ );
78
+ respondersMap.set(responder, responderInstance);
79
+}
80
+
81
+function updateEventListener(
82
+ listener: ReactEventResponderListener<any, any>,
83
+ fiber: Fiber,
84
+ visistedResponders: Set<ReactEventResponder<any, any>>,
85
+ respondersMap: Map<
86
+ ReactEventResponder<any, any>,
87
+ ReactEventResponderInstance<any, any>,
88
+ >,
89
+ instance: Instance,
90
+): void {
91
+ let responder;
92
+ let props;
93
+
94
+ if (listener) {
95
+ responder = listener.responder;
96
+ props = listener.props;
97
+ }
98
+ invariant(
99
+ responder && responder.$$typeof === REACT_RESPONDER_TYPE,
100
+ 'An invalid value was used as an event listener. Expect one or many event ' +
101
+ 'listeners created via React.unstable_useResponder().',
102
+ );
103
+ const listenerProps = ((props: any): Object);
104
+ if (visistedResponders.has(responder)) {
105
+ // show warning
106
+ if (__DEV__) {
107
+ warning(
108
+ false,
109
+ 'Duplicate event responder "%s" found in event listeners. ' +
110
+ 'Event listeners passed to elements cannot use the same event responder more than once.',
111
+ responder.displayName,
112
+ );
113
+ }
114
+ return;
115
+ }
116
+ visistedResponders.add(responder);
117
+ const responderInstance = respondersMap.get(responder);
118
+
119
+ if (responderInstance === undefined) {
120
+ // Mount (happens in either complete or commit phase)
121
+ mountEventResponder(
122
+ responder,
123
+ listenerProps,
124
+ instance,
125
+ fiber,
126
+ respondersMap,
127
+ );
128
+ } else {
129
+ // Update (happens during commit phase only)
130
+ responderInstance.props = listenerProps;
131
+ responderInstance.fiber = fiber;
132
+ }
133
+}
134
+
135
+export function updateEventListeners(
136
+ listeners: any,
137
+ instance: Instance,
138
+ fiber: Fiber,
139
+): void {
140
+ const visistedResponders = new Set();
141
+ let dependencies = fiber.dependencies;
142
+ if (listeners != null) {
143
+ if (dependencies === null) {
144
+ dependencies = fiber.dependencies = {
145
+ expirationTime: NoWork,
146
+ firstContext: null,
147
+ responders: new Map(),
148
+ };
149
+ }
150
+ let respondersMap = dependencies.responders;
151
+ if (respondersMap === null) {
152
+ respondersMap = new Map();
153
+ }
154
+ if (isArray(listeners)) {
155
+ for (let i = 0, length = listeners.length; i < length; i++) {
156
+ const listener = listeners[i];
157
+ updateEventListener(
158
+ listener,
159
+ fiber,
160
+ visistedResponders,
161
+ respondersMap,
162
+ instance,
163
+ );
164
+ }
165
+ } else {
166
+ updateEventListener(
167
+ listeners,
168
+ fiber,
169
+ visistedResponders,
170
+ respondersMap,
171
+ instance,
172
+ );
173
+ }
174
+ }
175
+ if (dependencies !== null) {
176
+ const respondersMap = dependencies.responders;
177
+ if (respondersMap !== null) {
178
+ // Unmount
179
+ const mountedResponders = Array.from(respondersMap.keys());
180
+ for (let i = 0, length = mountedResponders.length; i < length; i++) {
181
+ const mountedResponder = mountedResponders[i];
182
+ if (!visistedResponders.has(mountedResponder)) {
183
+ const responderInstance = ((respondersMap.get(
184
+ mountedResponder,
185
+ ): any): ReactEventResponderInstance<any, any>);
186
+ unmountResponderInstance(responderInstance);
187
+ respondersMap.delete(mountedResponder);
188
+ }
189
+ }
190
+ }
191
+ }
192
+}
193
+
194
+export function createResponderListener(
195
+ responder: ReactEventResponder<any, any>,
196
+ props: Object,
197
+): ReactEventResponderListener<any, any> {
198
+ const eventResponderListener = {
199
+ responder,
200
+ props,
201
+ };
202
+ if (__DEV__) {
203
+ Object.freeze(eventResponderListener);
204
+ }
205
+ return eventResponderListener;
206
+}
packages/react-test-renderer/src/ReactTestHostConfig.js
-1
@@ -296,7 +296,6 @@ export function mountResponderInstance(
296
props: Object,
297
state: Object,
298
instance: Instance,
299
- rootContainerInstance: Container,
299
) {
300
// noop
301
}