@samitouri / QOS-React-2 / commits / 4c5698400f

[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 }