[react-interactions] Remove context.setTimeout & context.clearTimeout (#17000)
Dominic Gannaway committed
Oct 3, 2019 at 13:37 UTC
4c5698400f04bbc6d0b4bd766b0993d0bcb37609
7 files changed
+4
-267
packages/react-dom/src/events/DOMEventResponderSystem.js
+1
-91
@@ -56,19 +56,6 @@ export function setListenToResponderEventTypes(
56
listenToResponderEventTypesImpl = _listenToResponderEventTypesImpl;
57
}
58
59
-type ResponderTimeout = {|
60
- id: TimeoutID,
61
- timers: Map<number, ResponderTimer>,
62
-|};
63
-
64
-type ResponderTimer = {|
65
- instance: ReactDOMEventResponderInstance,
66
- func: () => void,
67
- id: number,
68
- timeStamp: number,
69
-|};
70
-
71
-const activeTimeouts: Map<number, ResponderTimeout> = new Map();
59
const rootEventTypesToEventResponderInstances: Map<
60
DOMTopLevelEventType | string,
61
Set<ReactDOMEventResponderInstance>,
@@ -80,9 +67,7 @@ const DoNotPropagateToNextResponder = 0;
67
const PropagateToNextResponder = 1;
68
69
let currentTimeStamp = 0;
83
-let currentTimers = new Map();
70
let currentInstance: null | ReactDOMEventResponderInstance = null;
85
-let currentTimerIDCounter = 0;
71
let currentDocument: null | Document = null;
72
let currentPropagationBehavior: PropagationBehavior = DoNotPropagateToNextResponder;
73
@@ -202,46 +187,6 @@ const eventResponderContext: ReactDOMResponderContext = {
187
}
188
}
189
},
205
- setTimeout(func: () => void, delay): number {
206
- validateResponderContext();
207
- if (currentTimers === null) {
208
- currentTimers = new Map();
209
- }
210
- let timeout = currentTimers.get(delay);
211
-
212
- const timerId = currentTimerIDCounter++;
213
- if (timeout === undefined) {
214
- const timers = new Map();
215
- const id = setTimeout(() => {
216
- processTimers(timers, delay);
217
- }, delay);
218
- timeout = {
219
- id,
220
- timers,
221
- };
222
- currentTimers.set(delay, timeout);
223
- }
224
- timeout.timers.set(timerId, {
225
- instance: ((currentInstance: any): ReactDOMEventResponderInstance),
226
- func,
227
- id: timerId,
228
- timeStamp: currentTimeStamp,
229
- });
230
- activeTimeouts.set(timerId, timeout);
231
- return timerId;
232
- },
233
- clearTimeout(timerId: number): void {
234
- validateResponderContext();
235
- const timeout = activeTimeouts.get(timerId);
236
-
237
- if (timeout !== undefined) {
238
- const timers = timeout.timers;
239
- timers.delete(timerId);
240
- if (timers.size === 0) {
241
- clearTimeout(timeout.id);
242
- }
243
- }
244
- },
190
getActiveDocument,
191
objectAssign: Object.assign,
192
getTimeStamp(): number {
@@ -340,33 +285,6 @@ function getActiveDocument(): Document {
285
return ((currentDocument: any): Document);
286
}
287
343
-function processTimers(
344
- timers: Map<number, ResponderTimer>,
345
- delay: number,
346
-): void {
347
- const timersArr = Array.from(timers.values());
348
- const previousInstance = currentInstance;
349
- const previousTimers = currentTimers;
350
- try {
351
- batchedEventUpdates(() => {
352
- for (let i = 0; i < timersArr.length; i++) {
353
- const {instance, func, id, timeStamp} = timersArr[i];
354
- currentInstance = instance;
355
- currentTimeStamp = timeStamp + delay;
356
- try {
357
- func();
358
- } finally {
359
- activeTimeouts.delete(id);
360
- }
361
- }
362
- });
363
- } finally {
364
- currentTimers = previousTimers;
365
- currentInstance = previousInstance;
366
- currentTimeStamp = 0;
367
- }
368
-}
369
-
288
function createDOMResponderEvent(
289
topLevelType: string,
290
nativeEvent: AnyNativeEvent,
@@ -510,7 +428,6 @@ export function mountEventResponder(
428
const onMount = responder.onMount;
429
if (onMount !== null) {
430
const previousInstance = currentInstance;
513
- const previousTimers = currentTimers;
431
currentInstance = responderInstance;
432
try {
433
batchedEventUpdates(() => {
@@ -518,7 +435,6 @@ export function mountEventResponder(
435
});
436
} finally {
437
currentInstance = previousInstance;
521
- currentTimers = previousTimers;
438
}
439
}
440
}
@@ -531,7 +447,6 @@ export function unmountEventResponder(
447
if (onUnmount !== null) {
448
let {props, state} = responderInstance;
449
const previousInstance = currentInstance;
534
- const previousTimers = currentTimers;
450
currentInstance = responderInstance;
451
try {
452
batchedEventUpdates(() => {
@@ -539,7 +454,6 @@ export function unmountEventResponder(
454
});
455
} finally {
456
currentInstance = previousInstance;
542
- currentTimers = previousTimers;
457
}
458
}
459
const rootEventTypesSet = responderInstance.rootEventTypes;
@@ -561,8 +475,7 @@ export function unmountEventResponder(
475
function validateResponderContext(): void {
476
invariant(
477
currentInstance !== null,
564
- 'An event responder context was used outside of an event cycle. ' +
565
- 'Use context.setTimeout() to use asynchronous responder context outside of event cycle .',
478
+ 'An event responder context was used outside of an event cycle.',
479
);
480
}
481
@@ -575,12 +488,10 @@ export function dispatchEventForResponderEventSystem(
488
): void {
489
if (enableFlareAPI) {
490
const previousInstance = currentInstance;
578
- const previousTimers = currentTimers;
491
const previousTimeStamp = currentTimeStamp;
492
const previousDocument = currentDocument;
493
const previousPropagationBehavior = currentPropagationBehavior;
494
currentPropagationBehavior = DoNotPropagateToNextResponder;
583
- currentTimers = null;
495
// nodeType 9 is DOCUMENT_NODE
496
currentDocument =
497
(nativeEventTarget: any).nodeType === 9
@@ -599,7 +510,6 @@ export function dispatchEventForResponderEventSystem(
510
);
511
});
512
} finally {
602
- currentTimers = previousTimers;
513
currentInstance = previousInstance;
514
currentTimeStamp = previousTimeStamp;
515
currentDocument = previousDocument;
packages/react-dom/src/events/__tests__/DOMEventResponderSystem-test.internal.js
-75
@@ -469,81 +469,6 @@ describe('DOMEventResponderSystem', () => {
469
expect(eventLog).toEqual(['magic event fired', 'magicclick', 'bubble']);
470
});
471
472
- it('async event dispatching works', () => {
473
- let eventLog = [];
474
- const buttonRef = React.createRef();
475
-
476
- function handleEvent(event, context, props, phase) {
477
- const pressEvent = {
478
- target: event.target,
479
- type: 'press',
480
- phase,
481
- timeStamp: context.getTimeStamp(),
482
- };
483
- context.dispatchEvent(pressEvent, props.onPress, DiscreteEvent);
484
-
485
- context.setTimeout(() => {
486
- const longPressEvent = {
487
- target: event.target,
488
- type: 'longpress',
489
- phase,
490
- timeStamp: context.getTimeStamp(),
491
- };
492
- context.dispatchEvent(longPressEvent, props.onLongPress, DiscreteEvent);
493
-
494
- const longPressChangeEvent = {
495
- target: event.target,
496
- type: 'longpresschange',
497
- phase,
498
- timeStamp: context.getTimeStamp(),
499
- };
500
- context.dispatchEvent(
501
- longPressChangeEvent,
502
- props.onLongPressChange,
503
- DiscreteEvent,
504
- );
505
- }, 500);
506
- }
507
-
508
- const TestResponder = createEventResponder({
509
- targetEventTypes: ['click'],
510
- onEvent: (event, context, props) => {
511
- handleEvent(event, context, props, 'bubble');
512
- },
513
- });
514
-
515
- function log(msg) {
516
- eventLog.push(msg);
517
- }
518
-
519
- const Test = () => {
520
- const listener = React.unstable_useResponder(TestResponder, {
521
- onPress: e => log('press ' + e.phase),
522
- onLongPress: e => log('longpress ' + e.phase),
523
- onLongPressChange: e => log('longpresschange ' + e.phase),
524
- });
525
-
526
- return (
527
- <button ref={buttonRef} listeners={listener}>
528
- Click me!
529
- </button>
530
- );
531
- };
532
-
533
- ReactDOM.render(<Test />, container);
534
-
535
- // Clicking the button should trigger the event responder onEvent()
536
- let buttonElement = buttonRef.current;
537
- dispatchClickEvent(buttonElement);
538
- jest.runAllTimers();
539
-
540
- expect(eventLog).toEqual([
541
- 'press bubble',
542
- 'longpress bubble',
543
- 'longpresschange bubble',
544
- ]);
545
- });
546
-
472
it('the event responder onMount() function should fire', () => {
473
let onMountFired = 0;
474
packages/react-interactions/events/README.md
-9
@@ -67,7 +67,6 @@ Defines the DOM events to listen to on the root of the app.
67
68
Defines the DOM events to listen to within the Event Responder subtree.
69
70
-
70
## ResponderContext
71
72
The Event Responder Context is exposed via the `context` argument for certain methods
@@ -78,10 +77,6 @@ on the `EventResponder` object.
77
This can be used to dynamically listen to events on the root of the app only
78
when it is necessary to do so.
79
81
-### clearTimeout(id: Symbol): void
82
-
83
-Clear a timeout defined using `context.setTimeout`.
84
-
80
### dispatchEvent(propName: string, event: CustomEvent, { discrete: boolean })
81
82
Dispatches a custom synthetic event. The `type` and `target` are required
@@ -109,7 +104,3 @@ is within the scope of the same responder, but owned by another Event Responder
104
### removeRootEventTypes(eventTypes: Array<ResponderEventType>)
105
106
Remove the root event types added with `addRootEventTypes`.
112
-
113
-### setTimeout(func: () => void, delay: number): Symbol
114
-
115
-This can be used to dispatch async events, e.g., those that fire after a delay.
packages/react-native-renderer/src/ReactFabricEventResponderSystem.js
+1
-87
@@ -42,18 +42,6 @@ const {
42
unstable_runWithPriority: runWithPriority,
43
} = Scheduler;
44
45
-type ResponderTimeout = {|
46
- id: TimeoutID,
47
- timers: Map<number, ResponderTimer>,
48
-|};
49
-
50
-type ResponderTimer = {|
51
- instance: ReactNativeEventResponderInstance,
52
- func: () => void,
53
- id: number,
54
- timeStamp: number,
55
-|};
56
-
45
type ReactNativeEventResponder = ReactEventResponder<
46
ReactNativeResponderEvent,
47
ReactNativeResponderContext,
@@ -66,16 +54,13 @@ type ReactNativeEventResponderInstance = ReactEventResponderInstance<
54
55
const {measureInWindow} = nativeFabricUIManager;
56
69
-const activeTimeouts: Map<number, ResponderTimeout> = new Map();
57
const rootEventTypesToEventResponderInstances: Map<
58
string,
59
Set<ReactNativeEventResponderInstance>,
60
> = new Map();
61
62
let currentTimeStamp = 0;
76
-let currentTimers = new Map();
63
let currentInstance: null | ReactNativeEventResponderInstance = null;
78
-let currentTimerIDCounter = 0;
64
65
const eventResponderContext: ReactNativeResponderContext = {
66
dispatchEvent(
@@ -168,46 +153,6 @@ const eventResponderContext: ReactNativeResponderContext = {
153
}
154
}
155
},
171
- setTimeout(func: () => void, delay): number {
172
- validateResponderContext();
173
- if (currentTimers === null) {
174
- currentTimers = new Map();
175
- }
176
- let timeout = currentTimers.get(delay);
177
-
178
- const timerId = currentTimerIDCounter++;
179
- if (timeout === undefined) {
180
- const timers = new Map();
181
- const id = setTimeout(() => {
182
- processTimers(timers, delay);
183
- }, delay);
184
- timeout = {
185
- id,
186
- timers,
187
- };
188
- currentTimers.set(delay, timeout);
189
- }
190
- timeout.timers.set(timerId, {
191
- instance: ((currentInstance: any): ReactNativeEventResponderInstance),
192
- func,
193
- id: timerId,
194
- timeStamp: currentTimeStamp,
195
- });
196
- activeTimeouts.set(timerId, timeout);
197
- return timerId;
198
- },
199
- clearTimeout(timerId: number): void {
200
- validateResponderContext();
201
- const timeout = activeTimeouts.get(timerId);
202
-
203
- if (timeout !== undefined) {
204
- const timers = timeout.timers;
205
- timers.delete(timerId);
206
- if (timers.size === 0) {
207
- clearTimeout(timeout.id);
208
- }
209
- }
210
- },
156
getTimeStamp(): number {
157
validateResponderContext();
158
return currentTimeStamp;
@@ -283,31 +228,6 @@ function getFiberFromTarget(
228
return ((target.canonical._internalInstanceHandle: any): Fiber) || null;
229
}
230
286
-function processTimers(
287
- timers: Map<number, ResponderTimer>,
288
- delay: number,
289
-): void {
290
- const timersArr = Array.from(timers.values());
291
- try {
292
- batchedEventUpdates(() => {
293
- for (let i = 0; i < timersArr.length; i++) {
294
- const {instance, func, id, timeStamp} = timersArr[i];
295
- currentInstance = instance;
296
- currentTimeStamp = timeStamp + delay;
297
- try {
298
- func();
299
- } finally {
300
- activeTimeouts.delete(id);
301
- }
302
- }
303
- });
304
- } finally {
305
- currentTimers = null;
306
- currentInstance = null;
307
- currentTimeStamp = 0;
308
- }
309
-}
310
-
231
function createFabricResponderEvent(
232
topLevelType: string,
233
nativeEvent: ReactFaricEvent,
@@ -323,8 +243,7 @@ function createFabricResponderEvent(
243
function validateResponderContext(): void {
244
invariant(
245
currentInstance,
326
- 'An event responder context was used outside of an event cycle. ' +
327
- 'Use context.setTimeout() to use asynchronous responder context outside of event cycle .',
246
+ 'An event responder context was used outside of an event cycle.',
247
);
248
}
249
@@ -429,9 +348,7 @@ export function dispatchEventForResponderEventSystem(
348
nativeEvent: ReactFaricEvent,
349
): void {
350
const previousInstance = currentInstance;
432
- const previousTimers = currentTimers;
351
const previousTimeStamp = currentTimeStamp;
434
- currentTimers = null;
352
// We might want to control timeStamp another way here
353
currentTimeStamp = Date.now();
354
try {
@@ -443,7 +360,6 @@ export function dispatchEventForResponderEventSystem(
360
);
361
});
362
} finally {
446
- currentTimers = previousTimers;
363
currentInstance = previousInstance;
364
currentTimeStamp = previousTimeStamp;
365
}
@@ -466,7 +382,6 @@ export function mountEventResponder(
382
});
383
} finally {
384
currentInstance = null;
469
- currentTimers = null;
385
}
386
}
387
}
@@ -487,7 +402,6 @@ export function unmountEventResponder(
402
});
403
} finally {
404
currentInstance = null;
490
- currentTimers = null;
405
}
406
}
407
const rootEventTypesSet = responderInstance.rootEventTypes;
packages/react-native-renderer/src/ReactNativeTypes.js
-2
@@ -227,8 +227,6 @@ export type ReactNativeResponderContext = {
227
): void,
228
addRootEventTypes: (rootEventTypes: Array<string>) => void,
229
removeRootEventTypes: (rootEventTypes: Array<string>) => void,
230
- setTimeout: (func: () => void, timeout: number) => number,
231
- clearTimeout: (timerId: number) => void,
230
getTimeStamp: () => number,
231
getResponderNode(): ReactNativeEventTarget | null,
232
};
packages/shared/ReactDOMTypes.js
-2
@@ -62,8 +62,6 @@ export type ReactDOMResponderContext = {
62
isTargetWithinResponderScope: (null | Element | Document) => boolean,
63
addRootEventTypes: (rootEventTypes: Array<string>) => void,
64
removeRootEventTypes: (rootEventTypes: Array<string>) => void,
65
- setTimeout: (func: () => void, timeout: number) => number,
66
- clearTimeout: (timerId: number) => void,
65
getActiveDocument(): Document,
66
objectAssign: Function,
67
getTimeStamp: () => number,
scripts/error-codes/codes.json
+2
-1
@@ -343,5 +343,6 @@
343
"342": "A React component suspended while rendering, but no fallback UI was specified.\n\nAdd a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.",
344
"343": "ReactDOMServer does not yet support scope components.",
345
"344": "Expected prepareToHydrateHostSuspenseInstance() to never be called. This error is likely caused by a bug in React. Please file an issue.",
346
- "345": "Root did not complete. This is a bug in React."
346
+ "345": "Root did not complete. This is a bug in React.",
347
+ "346": "An event responder context was used outside of an event cycle."
348
}