From 4c5698400f04bbc6d0b4bd766b0993d0bcb37609 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Thu, 3 Oct 2019 13:37:37 +0200 Subject: [PATCH] [react-interactions] Remove context.setTimeout & context.clearTimeout (#17000) --- .../src/events/DOMEventResponderSystem.js | 92 +------------------ .../DOMEventResponderSystem-test.internal.js | 75 --------------- packages/react-interactions/events/README.md | 9 -- .../src/ReactFabricEventResponderSystem.js | 88 +----------------- .../src/ReactNativeTypes.js | 2 - packages/shared/ReactDOMTypes.js | 2 - scripts/error-codes/codes.json | 3 +- 7 files changed, 4 insertions(+), 267 deletions(-) diff --git a/packages/react-dom/src/events/DOMEventResponderSystem.js b/packages/react-dom/src/events/DOMEventResponderSystem.js index 7cd5940a5eb5e..f7a2e51bc6341 100644 --- a/packages/react-dom/src/events/DOMEventResponderSystem.js +++ b/packages/react-dom/src/events/DOMEventResponderSystem.js @@ -56,19 +56,6 @@ export function setListenToResponderEventTypes( listenToResponderEventTypesImpl = _listenToResponderEventTypesImpl; } -type ResponderTimeout = {| - id: TimeoutID, - timers: Map, -|}; - -type ResponderTimer = {| - instance: ReactDOMEventResponderInstance, - func: () => void, - id: number, - timeStamp: number, -|}; - -const activeTimeouts: Map = new Map(); const rootEventTypesToEventResponderInstances: Map< DOMTopLevelEventType | string, Set, @@ -80,9 +67,7 @@ const DoNotPropagateToNextResponder = 0; const PropagateToNextResponder = 1; let currentTimeStamp = 0; -let currentTimers = new Map(); let currentInstance: null | ReactDOMEventResponderInstance = null; -let currentTimerIDCounter = 0; let currentDocument: null | Document = null; let currentPropagationBehavior: PropagationBehavior = DoNotPropagateToNextResponder; @@ -202,46 +187,6 @@ const eventResponderContext: ReactDOMResponderContext = { } } }, - setTimeout(func: () => void, delay): number { - validateResponderContext(); - if (currentTimers === null) { - currentTimers = new Map(); - } - let timeout = currentTimers.get(delay); - - const timerId = currentTimerIDCounter++; - if (timeout === undefined) { - const timers = new Map(); - const id = setTimeout(() => { - processTimers(timers, delay); - }, delay); - timeout = { - id, - timers, - }; - currentTimers.set(delay, timeout); - } - timeout.timers.set(timerId, { - instance: ((currentInstance: any): ReactDOMEventResponderInstance), - func, - id: timerId, - timeStamp: currentTimeStamp, - }); - activeTimeouts.set(timerId, timeout); - return timerId; - }, - clearTimeout(timerId: number): void { - validateResponderContext(); - const timeout = activeTimeouts.get(timerId); - - if (timeout !== undefined) { - const timers = timeout.timers; - timers.delete(timerId); - if (timers.size === 0) { - clearTimeout(timeout.id); - } - } - }, getActiveDocument, objectAssign: Object.assign, getTimeStamp(): number { @@ -340,33 +285,6 @@ function getActiveDocument(): Document { return ((currentDocument: any): Document); } -function processTimers( - timers: Map, - delay: number, -): void { - const timersArr = Array.from(timers.values()); - const previousInstance = currentInstance; - const previousTimers = currentTimers; - try { - batchedEventUpdates(() => { - for (let i = 0; i < timersArr.length; i++) { - const {instance, func, id, timeStamp} = timersArr[i]; - currentInstance = instance; - currentTimeStamp = timeStamp + delay; - try { - func(); - } finally { - activeTimeouts.delete(id); - } - } - }); - } finally { - currentTimers = previousTimers; - currentInstance = previousInstance; - currentTimeStamp = 0; - } -} - function createDOMResponderEvent( topLevelType: string, nativeEvent: AnyNativeEvent, @@ -510,7 +428,6 @@ export function mountEventResponder( const onMount = responder.onMount; if (onMount !== null) { const previousInstance = currentInstance; - const previousTimers = currentTimers; currentInstance = responderInstance; try { batchedEventUpdates(() => { @@ -518,7 +435,6 @@ export function mountEventResponder( }); } finally { currentInstance = previousInstance; - currentTimers = previousTimers; } } } @@ -531,7 +447,6 @@ export function unmountEventResponder( if (onUnmount !== null) { let {props, state} = responderInstance; const previousInstance = currentInstance; - const previousTimers = currentTimers; currentInstance = responderInstance; try { batchedEventUpdates(() => { @@ -539,7 +454,6 @@ export function unmountEventResponder( }); } finally { currentInstance = previousInstance; - currentTimers = previousTimers; } } const rootEventTypesSet = responderInstance.rootEventTypes; @@ -561,8 +475,7 @@ export function unmountEventResponder( function validateResponderContext(): void { invariant( currentInstance !== null, - 'An event responder context was used outside of an event cycle. ' + - 'Use context.setTimeout() to use asynchronous responder context outside of event cycle .', + 'An event responder context was used outside of an event cycle.', ); } @@ -575,12 +488,10 @@ export function dispatchEventForResponderEventSystem( ): void { if (enableFlareAPI) { const previousInstance = currentInstance; - const previousTimers = currentTimers; const previousTimeStamp = currentTimeStamp; const previousDocument = currentDocument; const previousPropagationBehavior = currentPropagationBehavior; currentPropagationBehavior = DoNotPropagateToNextResponder; - currentTimers = null; // nodeType 9 is DOCUMENT_NODE currentDocument = (nativeEventTarget: any).nodeType === 9 @@ -599,7 +510,6 @@ export function dispatchEventForResponderEventSystem( ); }); } finally { - currentTimers = previousTimers; currentInstance = previousInstance; currentTimeStamp = previousTimeStamp; currentDocument = previousDocument; diff --git a/packages/react-dom/src/events/__tests__/DOMEventResponderSystem-test.internal.js b/packages/react-dom/src/events/__tests__/DOMEventResponderSystem-test.internal.js index c695a19fd3f61..65e01fff98c24 100644 --- a/packages/react-dom/src/events/__tests__/DOMEventResponderSystem-test.internal.js +++ b/packages/react-dom/src/events/__tests__/DOMEventResponderSystem-test.internal.js @@ -469,81 +469,6 @@ describe('DOMEventResponderSystem', () => { expect(eventLog).toEqual(['magic event fired', 'magicclick', 'bubble']); }); - it('async event dispatching works', () => { - let eventLog = []; - const buttonRef = React.createRef(); - - function handleEvent(event, context, props, phase) { - const pressEvent = { - target: event.target, - type: 'press', - phase, - timeStamp: context.getTimeStamp(), - }; - context.dispatchEvent(pressEvent, props.onPress, DiscreteEvent); - - context.setTimeout(() => { - const longPressEvent = { - target: event.target, - type: 'longpress', - phase, - timeStamp: context.getTimeStamp(), - }; - context.dispatchEvent(longPressEvent, props.onLongPress, DiscreteEvent); - - const longPressChangeEvent = { - target: event.target, - type: 'longpresschange', - phase, - timeStamp: context.getTimeStamp(), - }; - context.dispatchEvent( - longPressChangeEvent, - props.onLongPressChange, - DiscreteEvent, - ); - }, 500); - } - - const TestResponder = createEventResponder({ - targetEventTypes: ['click'], - onEvent: (event, context, props) => { - handleEvent(event, context, props, 'bubble'); - }, - }); - - function log(msg) { - eventLog.push(msg); - } - - const Test = () => { - const listener = React.unstable_useResponder(TestResponder, { - onPress: e => log('press ' + e.phase), - onLongPress: e => log('longpress ' + e.phase), - onLongPressChange: e => log('longpresschange ' + e.phase), - }); - - return ( - - ); - }; - - ReactDOM.render(, container); - - // Clicking the button should trigger the event responder onEvent() - let buttonElement = buttonRef.current; - dispatchClickEvent(buttonElement); - jest.runAllTimers(); - - expect(eventLog).toEqual([ - 'press bubble', - 'longpress bubble', - 'longpresschange bubble', - ]); - }); - it('the event responder onMount() function should fire', () => { let onMountFired = 0; diff --git a/packages/react-interactions/events/README.md b/packages/react-interactions/events/README.md index a8e093e7cd6ad..2c48c5a7bda3b 100644 --- a/packages/react-interactions/events/README.md +++ b/packages/react-interactions/events/README.md @@ -67,7 +67,6 @@ Defines the DOM events to listen to on the root of the app. Defines the DOM events to listen to within the Event Responder subtree. - ## ResponderContext The Event Responder Context is exposed via the `context` argument for certain methods @@ -78,10 +77,6 @@ on the `EventResponder` object. This can be used to dynamically listen to events on the root of the app only when it is necessary to do so. -### clearTimeout(id: Symbol): void - -Clear a timeout defined using `context.setTimeout`. - ### dispatchEvent(propName: string, event: CustomEvent, { discrete: boolean }) 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 ### removeRootEventTypes(eventTypes: Array) Remove the root event types added with `addRootEventTypes`. - -### setTimeout(func: () => void, delay: number): Symbol - -This can be used to dispatch async events, e.g., those that fire after a delay. diff --git a/packages/react-native-renderer/src/ReactFabricEventResponderSystem.js b/packages/react-native-renderer/src/ReactFabricEventResponderSystem.js index 4dec11e30e75a..c595a06fefdee 100644 --- a/packages/react-native-renderer/src/ReactFabricEventResponderSystem.js +++ b/packages/react-native-renderer/src/ReactFabricEventResponderSystem.js @@ -42,18 +42,6 @@ const { unstable_runWithPriority: runWithPriority, } = Scheduler; -type ResponderTimeout = {| - id: TimeoutID, - timers: Map, -|}; - -type ResponderTimer = {| - instance: ReactNativeEventResponderInstance, - func: () => void, - id: number, - timeStamp: number, -|}; - type ReactNativeEventResponder = ReactEventResponder< ReactNativeResponderEvent, ReactNativeResponderContext, @@ -66,16 +54,13 @@ type ReactNativeEventResponderInstance = ReactEventResponderInstance< const {measureInWindow} = nativeFabricUIManager; -const activeTimeouts: Map = new Map(); const rootEventTypesToEventResponderInstances: Map< string, Set, > = new Map(); let currentTimeStamp = 0; -let currentTimers = new Map(); let currentInstance: null | ReactNativeEventResponderInstance = null; -let currentTimerIDCounter = 0; const eventResponderContext: ReactNativeResponderContext = { dispatchEvent( @@ -168,46 +153,6 @@ const eventResponderContext: ReactNativeResponderContext = { } } }, - setTimeout(func: () => void, delay): number { - validateResponderContext(); - if (currentTimers === null) { - currentTimers = new Map(); - } - let timeout = currentTimers.get(delay); - - const timerId = currentTimerIDCounter++; - if (timeout === undefined) { - const timers = new Map(); - const id = setTimeout(() => { - processTimers(timers, delay); - }, delay); - timeout = { - id, - timers, - }; - currentTimers.set(delay, timeout); - } - timeout.timers.set(timerId, { - instance: ((currentInstance: any): ReactNativeEventResponderInstance), - func, - id: timerId, - timeStamp: currentTimeStamp, - }); - activeTimeouts.set(timerId, timeout); - return timerId; - }, - clearTimeout(timerId: number): void { - validateResponderContext(); - const timeout = activeTimeouts.get(timerId); - - if (timeout !== undefined) { - const timers = timeout.timers; - timers.delete(timerId); - if (timers.size === 0) { - clearTimeout(timeout.id); - } - } - }, getTimeStamp(): number { validateResponderContext(); return currentTimeStamp; @@ -283,31 +228,6 @@ function getFiberFromTarget( return ((target.canonical._internalInstanceHandle: any): Fiber) || null; } -function processTimers( - timers: Map, - delay: number, -): void { - const timersArr = Array.from(timers.values()); - try { - batchedEventUpdates(() => { - for (let i = 0; i < timersArr.length; i++) { - const {instance, func, id, timeStamp} = timersArr[i]; - currentInstance = instance; - currentTimeStamp = timeStamp + delay; - try { - func(); - } finally { - activeTimeouts.delete(id); - } - } - }); - } finally { - currentTimers = null; - currentInstance = null; - currentTimeStamp = 0; - } -} - function createFabricResponderEvent( topLevelType: string, nativeEvent: ReactFaricEvent, @@ -323,8 +243,7 @@ function createFabricResponderEvent( function validateResponderContext(): void { invariant( currentInstance, - 'An event responder context was used outside of an event cycle. ' + - 'Use context.setTimeout() to use asynchronous responder context outside of event cycle .', + 'An event responder context was used outside of an event cycle.', ); } @@ -429,9 +348,7 @@ export function dispatchEventForResponderEventSystem( nativeEvent: ReactFaricEvent, ): void { const previousInstance = currentInstance; - const previousTimers = currentTimers; const previousTimeStamp = currentTimeStamp; - currentTimers = null; // We might want to control timeStamp another way here currentTimeStamp = Date.now(); try { @@ -443,7 +360,6 @@ export function dispatchEventForResponderEventSystem( ); }); } finally { - currentTimers = previousTimers; currentInstance = previousInstance; currentTimeStamp = previousTimeStamp; } @@ -466,7 +382,6 @@ export function mountEventResponder( }); } finally { currentInstance = null; - currentTimers = null; } } } @@ -487,7 +402,6 @@ export function unmountEventResponder( }); } finally { currentInstance = null; - currentTimers = null; } } const rootEventTypesSet = responderInstance.rootEventTypes; diff --git a/packages/react-native-renderer/src/ReactNativeTypes.js b/packages/react-native-renderer/src/ReactNativeTypes.js index 1a7b69deb8ecf..fe42de3c62a58 100644 --- a/packages/react-native-renderer/src/ReactNativeTypes.js +++ b/packages/react-native-renderer/src/ReactNativeTypes.js @@ -227,8 +227,6 @@ export type ReactNativeResponderContext = { ): void, addRootEventTypes: (rootEventTypes: Array) => void, removeRootEventTypes: (rootEventTypes: Array) => void, - setTimeout: (func: () => void, timeout: number) => number, - clearTimeout: (timerId: number) => void, getTimeStamp: () => number, getResponderNode(): ReactNativeEventTarget | null, }; diff --git a/packages/shared/ReactDOMTypes.js b/packages/shared/ReactDOMTypes.js index 53bbb3384b145..c02bbd6447724 100644 --- a/packages/shared/ReactDOMTypes.js +++ b/packages/shared/ReactDOMTypes.js @@ -62,8 +62,6 @@ export type ReactDOMResponderContext = { isTargetWithinResponderScope: (null | Element | Document) => boolean, addRootEventTypes: (rootEventTypes: Array) => void, removeRootEventTypes: (rootEventTypes: Array) => void, - setTimeout: (func: () => void, timeout: number) => number, - clearTimeout: (timerId: number) => void, getActiveDocument(): Document, objectAssign: Function, getTimeStamp: () => number, diff --git a/scripts/error-codes/codes.json b/scripts/error-codes/codes.json index 5d0a777457745..a770a31c16c08 100644 --- a/scripts/error-codes/codes.json +++ b/scripts/error-codes/codes.json @@ -343,5 +343,6 @@ "342": "A React component suspended while rendering, but no fallback UI was specified.\n\nAdd a component higher in the tree to provide a loading indicator or placeholder to display.", "343": "ReactDOMServer does not yet support scope components.", "344": "Expected prepareToHydrateHostSuspenseInstance() to never be called. This error is likely caused by a bug in React. Please file an issue.", - "345": "Root did not complete. This is a bug in React." + "345": "Root did not complete. This is a bug in React.", + "346": "An event responder context was used outside of an event cycle." }