From 4eb9b1d2b4439853016a28091737cfdaa581b5db Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Tue, 7 Jul 2020 13:05:06 +0100 Subject: [PATCH] Refactor createEventHandle signature (#19174) --- packages/react-art/src/ReactARTHostConfig.js | 4 - .../src/client/ReactDOMEventHandle.js | 194 +++---- .../src/client/ReactDOMHostConfig.js | 21 +- .../src/events/DOMModernPluginEventSystem.js | 20 +- ...OMModernPluginEventSystem-test.internal.js | 540 ++++++++++++------ .../react-dom/src/shared/ReactDOMTypes.js | 12 +- .../src/dom/create-event-handle/useEvent.js | 44 +- .../src/ReactFabricHostConfig.js | 4 - .../src/ReactNativeHostConfig.js | 4 - .../src/createReactNoop.js | 6 - .../src/ReactFiberCommitWork.new.js | 10 - .../src/ReactFiberCommitWork.old.js | 10 - .../src/ReactFiberHostConfigWithNoScopes.js | 1 - .../src/forks/ReactFiberHostConfig.custom.js | 3 - .../src/ReactTestHostConfig.js | 8 - scripts/error-codes/codes.json | 5 +- 16 files changed, 497 insertions(+), 389 deletions(-) diff --git a/packages/react-art/src/ReactARTHostConfig.js b/packages/react-art/src/ReactARTHostConfig.js index fed5cf3cee..3362a3fd85 100644 --- a/packages/react-art/src/ReactARTHostConfig.js +++ b/packages/react-art/src/ReactARTHostConfig.js @@ -469,10 +469,6 @@ export function getInstanceFromNode(node) { throw new Error('Not yet implemented.'); } -export function removeInstanceEventHandles(instance) { - // noop -} - export function isOpaqueHydratingObject(value: mixed): boolean { throw new Error('Not yet implemented'); } diff --git a/packages/react-dom/src/client/ReactDOMEventHandle.js b/packages/react-dom/src/client/ReactDOMEventHandle.js index 64c76718e0..1ce1a760cc 100644 --- a/packages/react-dom/src/client/ReactDOMEventHandle.js +++ b/packages/react-dom/src/client/ReactDOMEventHandle.js @@ -47,6 +47,8 @@ type EventHandleOptions = {| priority?: EventPriority, |}; +const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set; + function getNearestRootOrPortalContainer(node: Fiber): null | Element { while (node !== null) { const tag = node.tag; @@ -72,12 +74,10 @@ function createEventHandleListener( type: DOMTopLevelEventType, capture: boolean, callback: (SyntheticEvent) => void, - destroy: (target: EventTarget | ReactScopeInstance) => void, ): ReactDOMEventHandleListener { return { callback, capture, - destroy, type, }; } @@ -111,6 +111,65 @@ function registerEventOnNearestTargetContainer( ); } +function registerReactDOMEvent( + target: EventTarget | ReactScopeInstance, + topLevelType: DOMTopLevelEventType, + passive: boolean | void, + capture: boolean, + priority: EventPriority | void, +): void { + // Check if the target is a DOM element. + if ((target: any).nodeType === ELEMENT_NODE) { + const targetElement = ((target: any): Element); + // Check if the DOM element is managed by React. + const targetFiber = getClosestInstanceFromNode(targetElement); + if (targetFiber === null) { + invariant( + false, + 'ReactDOM.createEventHandle: setListener called on an element ' + + 'target that is not managed by React. Ensure React rendered the DOM element.', + ); + } + registerEventOnNearestTargetContainer( + targetFiber, + topLevelType, + passive, + priority, + ); + } else if (enableScopeAPI && isReactScope(target)) { + const scopeTarget = ((target: any): ReactScopeInstance); + const targetFiber = getFiberFromScopeInstance(scopeTarget); + if (targetFiber === null) { + // Scope is unmounted, do not proceed. + return; + } + registerEventOnNearestTargetContainer( + targetFiber, + topLevelType, + passive, + priority, + ); + } else if (isValidEventTarget(target)) { + const eventTarget = ((target: any): EventTarget); + const listenerMap = getEventListenerMap(eventTarget); + listenToTopLevelEvent( + topLevelType, + eventTarget, + listenerMap, + PLUGIN_EVENT_SYSTEM | IS_TARGET_PHASE_ONLY, + capture, + passive, + priority, + ); + } else { + invariant( + false, + 'ReactDOM.createEventHandle: setter called on an invalid ' + + 'target. Provide a valid EventTarget or an element managed by React.', + ); + } +} + export function createEventHandle( type: string, options?: EventHandleOptions, @@ -140,110 +199,39 @@ export function createEventHandle( priority = getEventPriorityForListenerSystem(topLevelType); } - const listeners = new Map(); + const registeredReactDOMEvents = new PossiblyWeakSet(); - const destroy = (target: EventTarget | ReactScopeInstance): void => { - const listener = listeners.get(target); - if (listener !== undefined) { - listeners.delete(target); - const targetListeners = getEventHandlerListeners(target); - if (targetListeners !== null) { - targetListeners.delete(listener); - } + return ( + target: EventTarget | ReactScopeInstance, + callback: (SyntheticEvent) => void, + ) => { + invariant( + typeof callback === 'function', + 'ReactDOM.createEventHandle: setter called with an invalid ' + + 'callback. The callback must be a function.', + ); + if (!registeredReactDOMEvents.has(target)) { + registeredReactDOMEvents.add(target); + registerReactDOMEvent(target, topLevelType, passive, capture, priority); + // Add the event to our known event types list. + addEventTypeToDispatchConfig(topLevelType); } - }; - - const clear = (): void => { - const eventTargetsArr = Array.from(listeners.keys()); - for (let i = 0; i < eventTargetsArr.length; i++) { - destroy(eventTargetsArr[i]); + const listener = createEventHandleListener( + topLevelType, + capture, + callback, + ); + let targetListeners = getEventHandlerListeners(target); + if (targetListeners === null) { + targetListeners = new Set(); + setEventHandlerListeners(target, targetListeners); } - }; - - return { - setListener( - target: EventTarget | ReactScopeInstance, - callback: null | ((SyntheticEvent) => void), - ): void { - // Check if the target is a DOM element. - if ((target: any).nodeType === ELEMENT_NODE) { - const targetElement = ((target: any): Element); - // Check if the DOM element is managed by React. - const targetFiber = getClosestInstanceFromNode(targetElement); - if (targetFiber === null) { - invariant( - false, - 'ReactDOM.createEventHandle: setListener called on an element ' + - 'target that is not managed by React. Ensure React rendered the DOM element.', - ); - } - registerEventOnNearestTargetContainer( - targetFiber, - topLevelType, - passive, - priority, - ); - } else if (enableScopeAPI && isReactScope(target)) { - const scopeTarget = ((target: any): ReactScopeInstance); - const targetFiber = getFiberFromScopeInstance(scopeTarget); - if (targetFiber === null) { - // Scope is unmounted, do not proceed. - return; - } - registerEventOnNearestTargetContainer( - targetFiber, - topLevelType, - passive, - priority, - ); - } else if (isValidEventTarget(target)) { - const eventTarget = ((target: any): EventTarget); - const listenerMap = getEventListenerMap(eventTarget); - listenToTopLevelEvent( - topLevelType, - eventTarget, - listenerMap, - PLUGIN_EVENT_SYSTEM | IS_TARGET_PHASE_ONLY, - capture, - passive, - priority, - ); - } else { - invariant( - false, - 'ReactDOM.createEventHandle: setListener called on an invalid ' + - 'target. Provide a valid EventTarget or an element managed by React.', - ); - } - let listener = listeners.get(target); - if (listener === undefined) { - if (callback === null) { - return; - } - listener = createEventHandleListener( - topLevelType, - capture, - callback, - destroy, - ); - listeners.set(target, listener); - - let targetListeners = getEventHandlerListeners(target); - if (targetListeners === null) { - targetListeners = new Set(); - setEventHandlerListeners(target, targetListeners); - } - targetListeners.add(listener); - // Finally, add the event to our known event types list. - addEventTypeToDispatchConfig(topLevelType); - } else if (callback !== null) { - listener.callback = callback; - } else { - // Remove listener - destroy(target); - } - }, - clear, + targetListeners.add(listener); + return () => { + ((targetListeners: any): Set).delete( + listener, + ); + }; }; } return (null: any); diff --git a/packages/react-dom/src/client/ReactDOMHostConfig.js b/packages/react-dom/src/client/ReactDOMHostConfig.js index f794a3ded8..a06abe7614 100644 --- a/packages/react-dom/src/client/ReactDOMHostConfig.js +++ b/packages/react-dom/src/client/ReactDOMHostConfig.js @@ -80,10 +80,7 @@ import { } from 'shared/ReactFeatureFlags'; import {HostComponent, HostText} from 'react-reconciler/src/ReactWorkTags'; import {TOP_BEFORE_BLUR, TOP_AFTER_BLUR} from '../events/DOMTopLevelEventTypes'; -import { - listenToReactPropEvent, - clearEventHandleListenersForTarget, -} from '../events/DOMModernPluginEventSystem'; +import {listenToReactPropEvent} from '../events/DOMModernPluginEventSystem'; export type Type = string; export type Props = { @@ -534,14 +531,6 @@ function dispatchAfterDetachedBlur(target: HTMLElement): void { } } -export function removeInstanceEventHandles( - instance: Instance | TextInstance | SuspenseInstance, -) { - if (enableCreateEventHandleAPI) { - clearEventHandleListenersForTarget(instance); - } -} - export function removeChild( parentInstance: Instance, child: Instance | TextInstance | SuspenseInstance, @@ -1134,14 +1123,6 @@ export function prepareScopeUpdate( } } -export function removeScopeEventHandles( - scopeInstance: ReactScopeInstance, -): void { - if (enableScopeAPI && enableCreateEventHandleAPI) { - clearEventHandleListenersForTarget(scopeInstance); - } -} - export function getInstanceFromScope( scopeInstance: ReactScopeInstance, ): null | Object { diff --git a/packages/react-dom/src/events/DOMModernPluginEventSystem.js b/packages/react-dom/src/events/DOMModernPluginEventSystem.js index f1d95fe5a2..ccfdf65469 100644 --- a/packages/react-dom/src/events/DOMModernPluginEventSystem.js +++ b/packages/react-dom/src/events/DOMModernPluginEventSystem.js @@ -21,7 +21,7 @@ import type { ElementListenerMap, ElementListenerMapEntry, } from '../client/ReactDOMComponentTree'; -import type {EventPriority, ReactScopeInstance} from 'shared/ReactTypes'; +import type {EventPriority} from 'shared/ReactTypes'; import type {Fiber} from 'react-reconciler/src/ReactInternalTypes'; import {registrationNameDependencies} from './EventRegistry'; @@ -954,24 +954,6 @@ export function addEventTypeToDispatchConfig(type: DOMTopLevelEventType): void { } } -export function clearEventHandleListenersForTarget( - target: EventTarget | ReactScopeInstance, -): void { - // It's unfortunate that we have to do this cleanup, but - // it's necessary otherwise we will leak the host instances - // on the createEventHandle API "listeners" Map. We call destroy - // on each listener to ensure we properly remove the instance - // from the listeners Map. Note: we have this Map so that we - // can track listeners for the handle.clear() API call. - const listeners = getEventHandlerListeners(target); - if (listeners !== null) { - const listenersArr = Array.from(listeners); - for (let i = 0; i < listenersArr.length; i++) { - listenersArr[i].destroy(target); - } - } -} - export function getListenerMapKey( topLevelType: DOMTopLevelEventType, capture: boolean, diff --git a/packages/react-dom/src/events/__tests__/DOMModernPluginEventSystem-test.internal.js b/packages/react-dom/src/events/__tests__/DOMModernPluginEventSystem-test.internal.js index 9e5b09e8b0..195d6df3e5 100644 --- a/packages/react-dom/src/events/__tests__/DOMModernPluginEventSystem-test.internal.js +++ b/packages/react-dom/src/events/__tests__/DOMModernPluginEventSystem-test.internal.js @@ -1208,13 +1208,13 @@ describe('DOMModernPluginEventSystem', () => { // @gate experimental it('can render correctly with the ReactDOMServer', () => { const clickEvent = jest.fn(); - const click = ReactDOM.unstable_createEventHandle('click'); + const setClick = ReactDOM.unstable_createEventHandle('click'); function Test() { const divRef = React.useRef(null); React.useEffect(() => { - click.setListener(divRef.current, clickEvent); + return setClick(divRef.current, clickEvent); }); return
Hello world
; @@ -1227,11 +1227,11 @@ describe('DOMModernPluginEventSystem', () => { it('can render correctly with the ReactDOMServer hydration', () => { const clickEvent = jest.fn(); const spanRef = React.createRef(); - const click = ReactDOM.unstable_createEventHandle('click'); + const setClick = ReactDOM.unstable_createEventHandle('click'); function Test() { React.useEffect(() => { - click.setListener(spanRef.current, clickEvent); + return setClick(spanRef.current, clickEvent); }); return ( @@ -1264,11 +1264,11 @@ describe('DOMModernPluginEventSystem', () => { }); const divRef = React.createRef(); const buttonRef = React.createRef(); - const click = ReactDOM.unstable_createEventHandle('click'); + const setClick = ReactDOM.unstable_createEventHandle('click'); function Test() { React.useEffect(() => { - click.setListener(buttonRef.current, clickEvent); + return setClick(buttonRef.current, clickEvent); }); return ( @@ -1327,11 +1327,11 @@ describe('DOMModernPluginEventSystem', () => { }, ]); - const click2 = ReactDOM.unstable_createEventHandle('click'); + const setClick2 = ReactDOM.unstable_createEventHandle('click'); function Test2({clickEvent2}) { React.useEffect(() => { - click2.setListener(buttonRef.current, clickEvent2); + return setClick2(buttonRef.current, clickEvent2); }); return ( @@ -1364,18 +1364,16 @@ describe('DOMModernPluginEventSystem', () => { const clickEvent = jest.fn(); const divRef = React.createRef(); const buttonRef = React.createRef(); - const click = ReactDOM.unstable_createEventHandle('click'); + const setClick = ReactDOM.unstable_createEventHandle('click'); function Test({off}) { React.useEffect(() => { - click.setListener(buttonRef.current, clickEvent); - }); - - React.useEffect(() => { + const clear = setClick(buttonRef.current, clickEvent); if (off) { - click.setListener(buttonRef.current, null); + clear(); } - }, [off]); + return clear; + }); return ( ; @@ -1433,17 +1431,33 @@ describe('DOMModernPluginEventSystem', () => { const onClickCapture = jest.fn(e => log.push(['capture', e.currentTarget]), ); - const click = ReactDOM.unstable_createEventHandle('click'); - const clickCapture = ReactDOM.unstable_createEventHandle('click', { - capture: true, - }); + const setClick = ReactDOM.unstable_createEventHandle('click'); + const setCaptureClick = ReactDOM.unstable_createEventHandle( + 'click', + { + capture: true, + }, + ); function Test() { React.useEffect(() => { - click.setListener(buttonRef.current, onClick); - clickCapture.setListener(buttonRef.current, onClickCapture); - click.setListener(divRef.current, onClick); - clickCapture.setListener(divRef.current, onClickCapture); + const clearClick1 = setClick(buttonRef.current, onClick); + const clearCaptureClick1 = setCaptureClick( + buttonRef.current, + onClickCapture, + ); + const clearClick2 = setClick(divRef.current, onClick); + const clearCaptureClick2 = setCaptureClick( + divRef.current, + onClickCapture, + ); + + return () => { + clearClick1(); + clearCaptureClick1(); + clearClick2(); + clearCaptureClick2(); + }; }); return ( @@ -1486,15 +1500,23 @@ describe('DOMModernPluginEventSystem', () => { const onClickCapture = jest.fn(e => log.push(['capture', e.currentTarget]), ); - const click = ReactDOM.unstable_createEventHandle('click'); - const clickCapture = ReactDOM.unstable_createEventHandle('click', { - capture: true, - }); + const setClick = ReactDOM.unstable_createEventHandle('click'); + const setClickCapture = ReactDOM.unstable_createEventHandle( + 'click', + { + capture: true, + }, + ); function Test() { React.useEffect(() => { - click.setListener(buttonRef.current, onClick); - clickCapture.setListener(buttonRef.current, onClickCapture); + setClick(buttonRef.current, onClick); + setClickCapture(buttonRef.current, onClickCapture); + + return () => { + setClick(); + setClickCapture(); + }; }); return ( @@ -1542,11 +1564,11 @@ describe('DOMModernPluginEventSystem', () => { }); const divRef = React.createRef(); const buttonRef = React.createRef(); - const click = ReactDOM.unstable_createEventHandle('click'); + const setClick = ReactDOM.unstable_createEventHandle('click'); function Test() { React.useEffect(() => { - click.setListener(divRef.current, clickEvent); + return setClick(divRef.current, clickEvent); }); return ( @@ -1601,21 +1623,28 @@ describe('DOMModernPluginEventSystem', () => { const targetListener2 = jest.fn(); const targetListener3 = jest.fn(); const targetListener4 = jest.fn(); - let click1 = ReactDOM.unstable_createEventHandle('click', { + let setClick1 = ReactDOM.unstable_createEventHandle('click', { capture: true, }); - let click2 = ReactDOM.unstable_createEventHandle('click', { + let setClick2 = ReactDOM.unstable_createEventHandle('click', { capture: true, }); - let click3 = ReactDOM.unstable_createEventHandle('click'); - let click4 = ReactDOM.unstable_createEventHandle('click'); + let setClick3 = ReactDOM.unstable_createEventHandle('click'); + let setClick4 = ReactDOM.unstable_createEventHandle('click'); function Test() { React.useEffect(() => { - click1.setListener(buttonRef.current, targetListener1); - click2.setListener(buttonRef.current, targetListener2); - click3.setListener(buttonRef.current, targetListener3); - click4.setListener(buttonRef.current, targetListener4); + setClick1(buttonRef.current, targetListener1); + setClick2(buttonRef.current, targetListener2); + setClick3(buttonRef.current, targetListener3); + setClick4(buttonRef.current, targetListener4); + + return () => { + setClick1(); + setClick2(); + setClick3(); + setClick4(); + }; }); return ; @@ -1632,17 +1661,24 @@ describe('DOMModernPluginEventSystem', () => { expect(targetListener3).toHaveBeenCalledTimes(1); expect(targetListener4).toHaveBeenCalledTimes(1); - click1 = ReactDOM.unstable_createEventHandle('click'); - click2 = ReactDOM.unstable_createEventHandle('click'); - click3 = ReactDOM.unstable_createEventHandle('click'); - click4 = ReactDOM.unstable_createEventHandle('click'); + setClick1 = ReactDOM.unstable_createEventHandle('click'); + setClick2 = ReactDOM.unstable_createEventHandle('click'); + setClick3 = ReactDOM.unstable_createEventHandle('click'); + setClick4 = ReactDOM.unstable_createEventHandle('click'); function Test2() { React.useEffect(() => { - click1.setListener(buttonRef.current, targetListener1); - click2.setListener(buttonRef.current, targetListener2); - click3.setListener(buttonRef.current, targetListener3); - click4.setListener(buttonRef.current, targetListener4); + setClick1(buttonRef.current, targetListener1); + setClick2(buttonRef.current, targetListener2); + setClick3(buttonRef.current, targetListener3); + setClick4(buttonRef.current, targetListener4); + + return () => { + setClick1(); + setClick2(); + setClick3(); + setClick4(); + }; }); return ; @@ -1664,17 +1700,22 @@ describe('DOMModernPluginEventSystem', () => { const buttonRef = React.createRef(); const divRef = React.createRef(); const clickEvent = jest.fn(); - const click1 = ReactDOM.unstable_createEventHandle('click', { + const setClick1 = ReactDOM.unstable_createEventHandle('click', { bind: buttonRef, }); - const click2 = ReactDOM.unstable_createEventHandle('click'); + const setClick2 = ReactDOM.unstable_createEventHandle('click'); function Test() { React.useEffect(() => { - click1.setListener(buttonRef.current, clickEvent); - click2.setListener(divRef.current, e => { + const clearClick1 = setClick1(buttonRef.current, clickEvent); + const clearClick2 = setClick2(divRef.current, e => { e.stopPropagation(); }); + + return () => { + clearClick1(); + clearClick2(); + }; }); return ( @@ -1699,17 +1740,36 @@ describe('DOMModernPluginEventSystem', () => { const targetListener2 = jest.fn(e => e.stopPropagation()); const targetListener3 = jest.fn(e => e.stopPropagation()); const targetListener4 = jest.fn(e => e.stopPropagation()); - const click1 = ReactDOM.unstable_createEventHandle('click'); - const click2 = ReactDOM.unstable_createEventHandle('click'); - const click3 = ReactDOM.unstable_createEventHandle('click'); - const click4 = ReactDOM.unstable_createEventHandle('click'); + const setClick1 = ReactDOM.unstable_createEventHandle('click'); + const setClick2 = ReactDOM.unstable_createEventHandle('click'); + const setClick3 = ReactDOM.unstable_createEventHandle('click'); + const setClick4 = ReactDOM.unstable_createEventHandle('click'); function Test() { React.useEffect(() => { - click1.setListener(buttonRef.current, targetListener1); - click2.setListener(buttonRef.current, targetListener2); - click3.setListener(buttonRef.current, targetListener3); - click4.setListener(buttonRef.current, targetListener4); + const clearClick1 = setClick1( + buttonRef.current, + targetListener1, + ); + const clearClick2 = setClick2( + buttonRef.current, + targetListener2, + ); + const clearClick3 = setClick3( + buttonRef.current, + targetListener3, + ); + const clearClick4 = setClick4( + buttonRef.current, + targetListener4, + ); + + return () => { + clearClick1(); + clearClick2(); + clearClick3(); + clearClick4(); + }; }); return ; @@ -1733,21 +1793,40 @@ describe('DOMModernPluginEventSystem', () => { const targetListener2 = jest.fn(e => e.stopPropagation()); const targetListener3 = jest.fn(e => e.stopPropagation()); const targetListener4 = jest.fn(e => e.stopPropagation()); - const click1 = ReactDOM.unstable_createEventHandle('click', { + const setClick1 = ReactDOM.unstable_createEventHandle('click', { capture: true, }); - const click2 = ReactDOM.unstable_createEventHandle('click', { + const setClick2 = ReactDOM.unstable_createEventHandle('click', { capture: true, }); - const click3 = ReactDOM.unstable_createEventHandle('click'); - const click4 = ReactDOM.unstable_createEventHandle('click'); + const setClick3 = ReactDOM.unstable_createEventHandle('click'); + const setClick4 = ReactDOM.unstable_createEventHandle('click'); function Test() { React.useEffect(() => { - click1.setListener(buttonRef.current, targetListener1); - click2.setListener(buttonRef.current, targetListener2); - click3.setListener(buttonRef.current, targetListener3); - click4.setListener(buttonRef.current, targetListener4); + const clearClick1 = setClick1( + buttonRef.current, + targetListener1, + ); + const clearClick2 = setClick2( + buttonRef.current, + targetListener2, + ); + const clearClick3 = setClick3( + buttonRef.current, + targetListener3, + ); + const clearClick4 = setClick4( + buttonRef.current, + targetListener4, + ); + + return () => { + clearClick1(); + clearClick2(); + clearClick3(); + clearClick4(); + }; }); return ; @@ -1768,11 +1847,11 @@ describe('DOMModernPluginEventSystem', () => { it('should work with concurrent mode updates', async () => { const log = []; const ref = React.createRef(); - const click = ReactDOM.unstable_createEventHandle('click'); + const setClick1 = ReactDOM.unstable_createEventHandle('click'); function Test({counter}) { React.useLayoutEffect(() => { - click.setListener(ref.current, () => { + return setClick1(ref.current, () => { log.push({counter}); }); }); @@ -1816,16 +1895,16 @@ describe('DOMModernPluginEventSystem', () => { const clickEvent = jest.fn(); const buttonRef = React.createRef(); const button2Ref = React.createRef(); - const click = ReactDOM.unstable_createEventHandle('click', { + const setClick1 = ReactDOM.unstable_createEventHandle('click', { passive: false, }); - const click2 = ReactDOM.unstable_createEventHandle('click', { + const setClick2 = ReactDOM.unstable_createEventHandle('click', { passive: true, }); function Test2() { React.useEffect(() => { - click.setListener(button2Ref.current, clickEvent); + return setClick1(button2Ref.current, clickEvent); }); return ; @@ -1833,7 +1912,7 @@ describe('DOMModernPluginEventSystem', () => { function Test({extra}) { React.useEffect(() => { - click2.setListener(buttonRef.current, clickEvent); + return setClick2(buttonRef.current, clickEvent); }); return ( @@ -1866,16 +1945,16 @@ describe('DOMModernPluginEventSystem', () => { const clickEvent = jest.fn(); const buttonRef = React.createRef(); const button2Ref = React.createRef(); - const click = ReactDOM.unstable_createEventHandle('click', { + const setClick1 = ReactDOM.unstable_createEventHandle('click', { passive: false, }); - const click2 = ReactDOM.unstable_createEventHandle('click', { + const setClick2 = ReactDOM.unstable_createEventHandle('click', { passive: undefined, }); function Test2() { React.useEffect(() => { - click.setListener(button2Ref.current, clickEvent); + return setClick1(button2Ref.current, clickEvent); }); return ; @@ -1883,7 +1962,7 @@ describe('DOMModernPluginEventSystem', () => { function Test({extra}) { React.useEffect(() => { - click2.setListener(buttonRef.current, clickEvent); + return setClick2(buttonRef.current, clickEvent); }); return ( @@ -1922,15 +2001,11 @@ describe('DOMModernPluginEventSystem', () => { target: event.target, }); }); - const click = ReactDOM.unstable_createEventHandle('click'); + const setClick1 = ReactDOM.unstable_createEventHandle('click'); function Test() { React.useEffect(() => { - click.setListener(window, clickEvent); - - return () => { - click.setListener(window, null); - }; + return setClick1(window, clickEvent); }); return ; @@ -1975,23 +2050,39 @@ describe('DOMModernPluginEventSystem', () => { const onClickCapture = jest.fn(e => log.push(['capture', e.currentTarget]), ); - const click = ReactDOM.unstable_createEventHandle('click'); - const clickCapture = ReactDOM.unstable_createEventHandle('click', { - capture: true, - }); + const setClick = ReactDOM.unstable_createEventHandle('click'); + const setClickCapture = ReactDOM.unstable_createEventHandle( + 'click', + { + capture: true, + }, + ); function Test() { React.useEffect(() => { - click.setListener(window, onClick); - clickCapture.setListener(window, onClickCapture); - click.setListener(buttonRef.current, onClick); - clickCapture.setListener(buttonRef.current, onClickCapture); - click.setListener(divRef.current, onClick); - clickCapture.setListener(divRef.current, onClickCapture); + const clearClick1 = setClick(window, onClick); + const clearClickCapture1 = setClickCapture( + window, + onClickCapture, + ); + const clearClick2 = setClick(buttonRef.current, onClick); + const clearClickCapture2 = setClickCapture( + buttonRef.current, + onClickCapture, + ); + const clearClick3 = setClick(divRef.current, onClick); + const clearClickCapture3 = setClickCapture( + divRef.current, + onClickCapture, + ); return () => { - click.setListener(window, null); - clickCapture.setListener(window, null); + clearClick1(); + clearClickCapture1(); + clearClick2(); + clearClickCapture2(); + clearClick3(); + clearClickCapture3(); }; }); @@ -2037,25 +2128,33 @@ describe('DOMModernPluginEventSystem', () => { const rootListener2 = jest.fn(); const targetListener1 = jest.fn(); const targetListener2 = jest.fn(); - const click1 = ReactDOM.unstable_createEventHandle('click', { + const setClick1 = ReactDOM.unstable_createEventHandle('click', { capture: true, }); - const click2 = ReactDOM.unstable_createEventHandle('click', { + const setClick2 = ReactDOM.unstable_createEventHandle('click', { capture: true, }); - const click3 = ReactDOM.unstable_createEventHandle('click'); - const click4 = ReactDOM.unstable_createEventHandle('click'); + const setClick3 = ReactDOM.unstable_createEventHandle('click'); + const setClick4 = ReactDOM.unstable_createEventHandle('click'); function Test() { React.useEffect(() => { - click1.setListener(window, rootListener1); - click2.setListener(buttonRef.current, targetListener1); - click3.setListener(window, rootListener2); - click4.setListener(buttonRef.current, targetListener2); + const clearClick1 = setClick1(window, rootListener1); + const clearClick2 = setClick2( + buttonRef.current, + targetListener1, + ); + const clearClick3 = setClick3(window, rootListener2); + const clearClick4 = setClick4( + buttonRef.current, + targetListener2, + ); return () => { - click1.setListener(window, null); - click3.setListener(window, null); + clearClick1(); + clearClick2(); + clearClick3(); + clearClick4(); }; }); @@ -2080,27 +2179,27 @@ describe('DOMModernPluginEventSystem', () => { const rootListener2 = jest.fn(); const rootListener3 = jest.fn(e => e.stopPropagation()); const rootListener4 = jest.fn(); - const click1 = ReactDOM.unstable_createEventHandle('click', { + const setClick1 = ReactDOM.unstable_createEventHandle('click', { capture: true, }); - const click2 = ReactDOM.unstable_createEventHandle('click', { + const setClick2 = ReactDOM.unstable_createEventHandle('click', { capture: true, }); - const click3 = ReactDOM.unstable_createEventHandle('click'); - const click4 = ReactDOM.unstable_createEventHandle('click'); + const setClick3 = ReactDOM.unstable_createEventHandle('click'); + const setClick4 = ReactDOM.unstable_createEventHandle('click'); function Test() { React.useEffect(() => { - click1.setListener(window, rootListener1); - click2.setListener(window, rootListener2); - click3.setListener(window, rootListener3); - click4.setListener(window, rootListener4); + const clearClick1 = setClick1(window, rootListener1); + const clearClick2 = setClick2(window, rootListener2); + const clearClick3 = setClick3(window, rootListener3); + const clearClick4 = setClick4(window, rootListener4); return () => { - click1.setListener(window, null); - click2.setListener(window, null); - click3.setListener(window, null); - click4.setListener(window, null); + clearClick1(); + clearClick2(); + clearClick3(); + clearClick4(); }; }); @@ -2128,27 +2227,46 @@ describe('DOMModernPluginEventSystem', () => { const onClickCapture = jest.fn(e => log.push(['capture', e.currentTarget]), ); - const click = ReactDOM.unstable_createEventHandle('click'); - const clickCapture = ReactDOM.unstable_createEventHandle('click', { - capture: true, - }); + const setClick = ReactDOM.unstable_createEventHandle('click'); + const setClickCapture = ReactDOM.unstable_createEventHandle( + 'click', + { + capture: true, + }, + ); function Test() { React.useEffect(() => { - click.setListener(window, onClick); - clickCapture.setListener(window, onClickCapture); - click.setListener(document, onClick); - clickCapture.setListener(document, onClickCapture); - click.setListener(buttonRef.current, onClick); - clickCapture.setListener(buttonRef.current, onClickCapture); - click.setListener(divRef.current, onClick); - clickCapture.setListener(divRef.current, onClickCapture); + const clearClick1 = setClick(window, onClick); + const clearClickCapture1 = setClickCapture( + window, + onClickCapture, + ); + const clearClick2 = setClick(document, onClick); + const clearClickCapture2 = setClickCapture( + document, + onClickCapture, + ); + const clearClick3 = setClick(buttonRef.current, onClick); + const clearClickCapture3 = setClickCapture( + buttonRef.current, + onClickCapture, + ); + const clearClick4 = setClick(divRef.current, onClick); + const clearClickCapture4 = setClickCapture( + divRef.current, + onClickCapture, + ); return () => { - click.setListener(window, null); - clickCapture.setListener(window, null); - click.setListener(document, null); - clickCapture.setListener(document, null); + clearClick1(); + clearClickCapture1(); + clearClick2(); + clearClickCapture2(); + clearClick3(); + clearClickCapture3(); + clearClick4(); + clearClickCapture4(); }; }); @@ -2225,11 +2343,11 @@ describe('DOMModernPluginEventSystem', () => { log.push(['capture', e.currentTarget]), ); - let customEventHandle; + let setCustomEventHandle; // Test that we get a warning when we don't provide an explicit priority expect(() => { - customEventHandle = ReactDOM.unstable_createEventHandle( + setCustomEventHandle = ReactDOM.unstable_createEventHandle( 'custom-event', ); }).toWarnDev( @@ -2238,14 +2356,14 @@ describe('DOMModernPluginEventSystem', () => { {withoutStack: true}, ); - customEventHandle = ReactDOM.unstable_createEventHandle( + setCustomEventHandle = ReactDOM.unstable_createEventHandle( 'custom-event', { priority: 0, // Discrete }, ); - const customCaptureHandle = ReactDOM.unstable_createEventHandle( + const setCustomCaptureHandle = ReactDOM.unstable_createEventHandle( 'custom-event', { capture: true, @@ -2255,16 +2373,29 @@ describe('DOMModernPluginEventSystem', () => { function Test() { React.useEffect(() => { - customEventHandle.setListener(buttonRef.current, onCustomEvent); - customCaptureHandle.setListener( + const clearCustom1 = setCustomEventHandle( + buttonRef.current, + onCustomEvent, + ); + const clearCustom2 = setCustomCaptureHandle( buttonRef.current, onCustomEventCapture, ); - customEventHandle.setListener(divRef.current, onCustomEvent); - customCaptureHandle.setListener( + const clearCustom3 = setCustomEventHandle( + divRef.current, + onCustomEvent, + ); + const clearCustom4 = setCustomCaptureHandle( divRef.current, onCustomEventCapture, ); + + return () => { + clearCustom1(); + clearCustom2(); + clearCustom3(); + clearCustom4(); + }; }); return ( @@ -2305,10 +2436,10 @@ describe('DOMModernPluginEventSystem', () => { const onBeforeBlur = jest.fn(e => log.push(e.type)); const innerRef = React.createRef(); const innerRef2 = React.createRef(); - const afterBlurHandle = ReactDOM.unstable_createEventHandle( + const setAfterBlurHandle = ReactDOM.unstable_createEventHandle( 'afterblur', ); - const beforeBlurHandle = ReactDOM.unstable_createEventHandle( + const setBeforeBlurHandle = ReactDOM.unstable_createEventHandle( 'beforeblur', ); @@ -2316,8 +2447,13 @@ describe('DOMModernPluginEventSystem', () => { const ref = React.useRef(null); React.useEffect(() => { - afterBlurHandle.setListener(document, onAfterBlur); - beforeBlurHandle.setListener(ref.current, onBeforeBlur); + const clear1 = setAfterBlurHandle(document, onAfterBlur); + const clear2 = setBeforeBlurHandle(ref.current, onBeforeBlur); + + return () => { + clear1(); + clear2(); + }; }); return ( @@ -2359,10 +2495,10 @@ describe('DOMModernPluginEventSystem', () => { const onBeforeBlur = jest.fn(e => log.push(e.type)); const innerRef = React.createRef(); const innerRef2 = React.createRef(); - const afterBlurHandle = ReactDOM.unstable_createEventHandle( + const setAfterBlurHandle = ReactDOM.unstable_createEventHandle( 'afterblur', ); - const beforeBlurHandle = ReactDOM.unstable_createEventHandle( + const setBeforeBlurHandle = ReactDOM.unstable_createEventHandle( 'beforeblur', ); @@ -2370,8 +2506,13 @@ describe('DOMModernPluginEventSystem', () => { const ref = React.useRef(null); React.useEffect(() => { - afterBlurHandle.setListener(document, onAfterBlur); - beforeBlurHandle.setListener(ref.current, onBeforeBlur); + const clear1 = setAfterBlurHandle(document, onAfterBlur); + const clear2 = setBeforeBlurHandle(ref.current, onBeforeBlur); + + return () => { + clear1(); + clear2(); + }; }); return ( @@ -2422,10 +2563,10 @@ describe('DOMModernPluginEventSystem', () => { const promise = new Promise( resolvePromise => (resolve = resolvePromise), ); - const afterBlurHandle = ReactDOM.unstable_createEventHandle( + const setAfterBlurHandle = ReactDOM.unstable_createEventHandle( 'afterblur', ); - const beforeBlurHandle = ReactDOM.unstable_createEventHandle( + const setBeforeBlurHandle = ReactDOM.unstable_createEventHandle( 'beforeblur', ); @@ -2441,8 +2582,13 @@ describe('DOMModernPluginEventSystem', () => { const ref = React.useRef(null); React.useEffect(() => { - afterBlurHandle.setListener(document, onAfterBlur); - beforeBlurHandle.setListener(ref.current, onBeforeBlur); + const clear1 = setAfterBlurHandle(document, onAfterBlur); + const clear2 = setBeforeBlurHandle(ref.current, onBeforeBlur); + + return () => { + clear1(); + clear2(); + }; }); return ( @@ -2492,7 +2638,7 @@ describe('DOMModernPluginEventSystem', () => { const Suspense = React.Suspense; let suspend = false; const promise = Promise.resolve(); - const beforeBlurHandle = ReactDOM.unstable_createEventHandle( + const setBeforeBlurHandle = ReactDOM.unstable_createEventHandle( 'beforeblur', ); const innerRef = React.createRef(); @@ -2509,7 +2655,7 @@ describe('DOMModernPluginEventSystem', () => { const [, setState] = React.useState(0); React.useEffect(() => { - beforeBlurHandle.setListener(ref.current, () => { + return setBeforeBlurHandle(ref.current, () => { // In the regression case, this would trigger an update, then // the resulting render would trigger another blur event, // which would trigger an update again, and on and on in an @@ -2573,8 +2719,8 @@ describe('DOMModernPluginEventSystem', () => { log.push(['capture', e.currentTarget]), ); const TestScope = React.unstable_createScope(); - const click = ReactDOM.unstable_createEventHandle('click'); - const clickCapture = ReactDOM.unstable_createEventHandle( + const setClick = ReactDOM.unstable_createEventHandle('click'); + const setClickCapture = ReactDOM.unstable_createEventHandle( 'click', { capture: true, @@ -2585,8 +2731,16 @@ describe('DOMModernPluginEventSystem', () => { const scopeRef = React.useRef(null); React.useEffect(() => { - click.setListener(scopeRef.current, onClick); - clickCapture.setListener(scopeRef.current, onClickCapture); + const clear1 = setClick(scopeRef.current, onClick); + const clear2 = setClickCapture( + scopeRef.current, + onClickCapture, + ); + + return () => { + clear1(); + clear2(); + }; }); return ( @@ -2622,8 +2776,8 @@ describe('DOMModernPluginEventSystem', () => { log.push(['capture', e.currentTarget]), ); const TestScope = React.unstable_createScope(); - const click = ReactDOM.unstable_createEventHandle('click'); - const clickCapture = ReactDOM.unstable_createEventHandle( + const setClick = ReactDOM.unstable_createEventHandle('click'); + const setClickCapture = ReactDOM.unstable_createEventHandle( 'click', { capture: true, @@ -2634,10 +2788,23 @@ describe('DOMModernPluginEventSystem', () => { const scopeRef = React.useRef(null); React.useEffect(() => { - click.setListener(scopeRef.current, onClick); - clickCapture.setListener(scopeRef.current, onClickCapture); - click.setListener(buttonRef.current, onClick); - clickCapture.setListener(buttonRef.current, onClickCapture); + const clear1 = setClick(scopeRef.current, onClick); + const clear2 = setClickCapture( + scopeRef.current, + onClickCapture, + ); + const clear3 = setClick(buttonRef.current, onClick); + const clear4 = setClickCapture( + buttonRef.current, + onClickCapture, + ); + + return () => { + clear1(); + clear2(); + clear3(); + clear4(); + }; }); return ( @@ -2693,13 +2860,13 @@ describe('DOMModernPluginEventSystem', () => { const clickEvent = jest.fn(); const buttonRef = React.createRef(); const TestScope = React.unstable_createScope(); - const click = ReactDOM.unstable_createEventHandle('click'); + const setClick = ReactDOM.unstable_createEventHandle('click'); function Test() { const scopeRef = React.useRef(null); React.useEffect(() => { - click.setListener(scopeRef.current, clickEvent); + return setClick(scopeRef.current, clickEvent); }); return ( @@ -2726,15 +2893,20 @@ describe('DOMModernPluginEventSystem', () => { const innerOnClick = jest.fn(e => e.stopPropagation()); const TestScope = React.unstable_createScope(); const TestScope2 = React.unstable_createScope(); - const click = ReactDOM.unstable_createEventHandle('click'); + const setClick = ReactDOM.unstable_createEventHandle('click'); function Test() { const scopeRef = React.useRef(null); const scope2Ref = React.useRef(null); React.useEffect(() => { - click.setListener(scopeRef.current, outerOnClick); - click.setListener(scope2Ref.current, innerOnClick); + const clear1 = setClick(scopeRef.current, outerOnClick); + const clear2 = setClick(scope2Ref.current, innerOnClick); + + return () => { + clear1(); + clear2(); + }; }); return ( @@ -2763,15 +2935,20 @@ describe('DOMModernPluginEventSystem', () => { const innerOnClick = jest.fn(); const TestScope = React.unstable_createScope(); const TestScope2 = React.unstable_createScope(); - const click = ReactDOM.unstable_createEventHandle('click'); + const setClick = ReactDOM.unstable_createEventHandle('click'); function Test() { const scopeRef = React.useRef(null); const scope2Ref = React.useRef(null); React.useEffect(() => { - click.setListener(scopeRef.current, outerOnClick); - click.setListener(scope2Ref.current, innerOnClick); + const clear1 = setClick(scopeRef.current, outerOnClick); + const clear2 = setClick(scope2Ref.current, innerOnClick); + + return () => { + clear1(); + clear2(); + }; }); return ( @@ -2799,15 +2976,20 @@ describe('DOMModernPluginEventSystem', () => { const onClick = jest.fn(e => e.stopPropagation()); const TestScope = React.unstable_createScope(); const TestScope2 = React.unstable_createScope(); - const click = ReactDOM.unstable_createEventHandle('click'); + const setClick = ReactDOM.unstable_createEventHandle('click'); function Test() { const scopeRef = React.useRef(null); const scope2Ref = React.useRef(null); React.useEffect(() => { - click.setListener(scopeRef.current, onClick); - click.setListener(scope2Ref.current, onClick); + const clear1 = setClick(scopeRef.current, onClick); + const clear2 = setClick(scope2Ref.current, onClick); + + return () => { + clear1(); + clear2(); + }; }); return ( diff --git a/packages/react-dom/src/shared/ReactDOMTypes.js b/packages/react-dom/src/shared/ReactDOMTypes.js index 3a04da5201..06f2fd6ac2 100644 --- a/packages/react-dom/src/shared/ReactDOMTypes.js +++ b/packages/react-dom/src/shared/ReactDOMTypes.js @@ -78,17 +78,13 @@ export type ReactDOMResponderContext = { ... }; -export type ReactDOMEventHandle = {| - setListener( - target: EventTarget | ReactScopeInstance, - callback: (SyntheticEvent) => void, - ): void, - clear(): void, -|}; +export type ReactDOMEventHandle = ( + target: EventTarget | ReactScopeInstance, + callback: (SyntheticEvent) => void, +) => () => void; export type ReactDOMEventHandleListener = {| callback: (SyntheticEvent) => void, capture: boolean, - destroy: (target: EventTarget | ReactScopeInstance) => void, type: DOMTopLevelEventType, |}; diff --git a/packages/react-interactions/events/src/dom/create-event-handle/useEvent.js b/packages/react-interactions/events/src/dom/create-event-handle/useEvent.js index ef9a0d17a2..0005162be6 100644 --- a/packages/react-interactions/events/src/dom/create-event-handle/useEvent.js +++ b/packages/react-interactions/events/src/dom/create-event-handle/useEvent.js @@ -10,7 +10,7 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; -const {useEffect, useRef} = React; +const {useLayoutEffect, useRef} = React; const {unstable_createEventHandle: createEventHandle} = ReactDOM; type UseEventHandle = {| @@ -30,20 +30,48 @@ export default function useEvent( |}, ): UseEventHandle { const handleRef = useRef(null); + let setListener; + let clears; + let useEventHandle; if (handleRef.current == null) { - handleRef.current = createEventHandle(event, options); + setListener = createEventHandle(event, options); + clears = new Map(); + useEventHandle = { + setListener( + target: EventTarget, + callback: null | ((SyntheticEvent) => void), + ): void { + let clear = clears.get(target); + if (clear !== undefined) { + clear(); + } + if (callback === null) { + clears.delete(target); + return; + } + clear = setListener(target, callback); + clears.set(target, clear); + }, + clear(): void { + const clearsArr = Array.from(clears.values()); + for (let i = 0; i < clearsArr.length; i++) { + clearsArr[i](); + } + clears.clear(); + }, + }; + handleRef.current = {setListener, clears, useEventHandle}; + } else { + ({setListener, clears, useEventHandle} = handleRef.current); } - useEffect(() => { - const handle = handleRef.current; + useLayoutEffect(() => { return () => { - if (handle !== null) { - handle.clear(); - } + useEventHandle.clear(); handleRef.current = null; }; }, []); - return ((handleRef.current: any): UseEventHandle); + return useEventHandle; } diff --git a/packages/react-native-renderer/src/ReactFabricHostConfig.js b/packages/react-native-renderer/src/ReactFabricHostConfig.js index f25ed6a25a..9300e5840a 100644 --- a/packages/react-native-renderer/src/ReactFabricHostConfig.js +++ b/packages/react-native-renderer/src/ReactFabricHostConfig.js @@ -479,10 +479,6 @@ export function getInstanceFromNode(node: any) { throw new Error('Not yet implemented.'); } -export function removeInstanceEventHandles(instance: any) { - // noop -} - export function isOpaqueHydratingObject(value: mixed): boolean { throw new Error('Not yet implemented'); } diff --git a/packages/react-native-renderer/src/ReactNativeHostConfig.js b/packages/react-native-renderer/src/ReactNativeHostConfig.js index 36eb8421db..4bcb576ca0 100644 --- a/packages/react-native-renderer/src/ReactNativeHostConfig.js +++ b/packages/react-native-renderer/src/ReactNativeHostConfig.js @@ -532,10 +532,6 @@ export function getInstanceFromNode(node: any) { throw new Error('Not yet implemented.'); } -export function removeInstanceEventHandles(instance: any) { - // noop -} - export function isOpaqueHydratingObject(value: mixed): boolean { throw new Error('Not yet implemented'); } diff --git a/packages/react-noop-renderer/src/createReactNoop.js b/packages/react-noop-renderer/src/createReactNoop.js index d6ed76cfcc..0290e44520 100644 --- a/packages/react-noop-renderer/src/createReactNoop.js +++ b/packages/react-noop-renderer/src/createReactNoop.js @@ -438,10 +438,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { throw new Error('Not yet implemented.'); }, - removeInstanceEventHandles(instance: any): void { - // NO-OP - }, - beforeActiveInstanceBlur() { // NO-OP }, @@ -456,8 +452,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { prepareScopeUpdate() {}, - removeScopeEventHandles() {}, - getInstanceFromScope() { throw new Error('Not yet implemented.'); }, diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js index 8e462c3bae..d854ae52aa 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js @@ -35,7 +35,6 @@ import { enableFundamentalAPI, enableSuspenseCallback, enableScopeAPI, - enableCreateEventHandleAPI, } from 'shared/ReactFeatureFlags'; import { FunctionComponent, @@ -109,10 +108,8 @@ import { updateFundamentalComponent, commitHydratedContainer, commitHydratedSuspenseInstance, - removeInstanceEventHandles, clearContainer, prepareScopeUpdate, - removeScopeEventHandles, } from './ReactFiberHostConfig'; import { captureCommitPhaseError, @@ -928,9 +925,6 @@ function commitUnmount( if (enableDeprecatedFlareAPI) { unmountDeprecatedResponderListeners(current); } - if (enableCreateEventHandleAPI && current.ref !== null) { - removeInstanceEventHandles(current.stateNode); - } safelyDetachRef(current); return; } @@ -972,10 +966,6 @@ function commitUnmount( if (enableDeprecatedFlareAPI) { unmountDeprecatedResponderListeners(current); } - const scopeInstance = current.stateNode; - if (enableCreateEventHandleAPI && current.ref !== null) { - removeScopeEventHandles(scopeInstance); - } safelyDetachRef(current); } return; diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.old.js b/packages/react-reconciler/src/ReactFiberCommitWork.old.js index c48b00988b..5d1c5e03a5 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.old.js @@ -35,7 +35,6 @@ import { enableFundamentalAPI, enableSuspenseCallback, enableScopeAPI, - enableCreateEventHandleAPI, } from 'shared/ReactFeatureFlags'; import { FunctionComponent, @@ -109,10 +108,8 @@ import { updateFundamentalComponent, commitHydratedContainer, commitHydratedSuspenseInstance, - removeInstanceEventHandles, clearContainer, prepareScopeUpdate, - removeScopeEventHandles, } from './ReactFiberHostConfig'; import { captureCommitPhaseError, @@ -928,9 +925,6 @@ function commitUnmount( if (enableDeprecatedFlareAPI) { unmountDeprecatedResponderListeners(current); } - if (enableCreateEventHandleAPI && current.ref !== null) { - removeInstanceEventHandles(current.stateNode); - } safelyDetachRef(current); return; } @@ -972,10 +966,6 @@ function commitUnmount( if (enableDeprecatedFlareAPI) { unmountDeprecatedResponderListeners(current); } - const scopeInstance = current.stateNode; - if (enableCreateEventHandleAPI && current.ref !== null) { - removeScopeEventHandles(scopeInstance); - } safelyDetachRef(current); } return; diff --git a/packages/react-reconciler/src/ReactFiberHostConfigWithNoScopes.js b/packages/react-reconciler/src/ReactFiberHostConfigWithNoScopes.js index 57e3756340..9c9c893767 100644 --- a/packages/react-reconciler/src/ReactFiberHostConfigWithNoScopes.js +++ b/packages/react-reconciler/src/ReactFiberHostConfigWithNoScopes.js @@ -23,5 +23,4 @@ function shim(...args: any) { // React Scopes (when unsupported) export const prepareScopeUpdate = shim; -export const removeScopeEventHandles = shim; export const getInstanceFromScope = shim; diff --git a/packages/react-reconciler/src/forks/ReactFiberHostConfig.custom.js b/packages/react-reconciler/src/forks/ReactFiberHostConfig.custom.js index d6f998634b..eae290fdbd 100644 --- a/packages/react-reconciler/src/forks/ReactFiberHostConfig.custom.js +++ b/packages/react-reconciler/src/forks/ReactFiberHostConfig.custom.js @@ -72,8 +72,6 @@ export const mountFundamentalComponent = export const shouldUpdateFundamentalComponent = $$$hostConfig.shouldUpdateFundamentalComponent; export const getInstanceFromNode = $$$hostConfig.getInstanceFromNode; -export const removeInstanceEventHandles = - $$$hostConfig.removeInstanceEventHandles; export const isOpaqueHydratingObject = $$$hostConfig.isOpaqueHydratingObject; export const makeOpaqueHydratingObject = $$$hostConfig.makeOpaqueHydratingObject; @@ -83,7 +81,6 @@ export const beforeActiveInstanceBlur = $$$hostConfig.beforeActiveInstanceBlur; export const afterActiveInstanceBlur = $$$hostConfig.afterActiveInstanceBlur; export const preparePortalMount = $$$hostConfig.preparePortalMount; export const prepareScopeUpdate = $$$hostConfig.preparePortalMount; -export const removeScopeEventHandles = $$$hostConfig.removeScopeEventHandles; export const getInstanceFromScope = $$$hostConfig.getInstanceFromScope; // ------------------- diff --git a/packages/react-test-renderer/src/ReactTestHostConfig.js b/packages/react-test-renderer/src/ReactTestHostConfig.js index 43dd94cc37..7b91c5aa5c 100644 --- a/packages/react-test-renderer/src/ReactTestHostConfig.js +++ b/packages/react-test-renderer/src/ReactTestHostConfig.js @@ -383,10 +383,6 @@ export function getInstanceFromNode(mockNode: Object) { return null; } -export function removeInstanceEventHandles(instance: any) { - // noop -} - let clientId: number = 0; export function makeClientId(): OpaqueIDType { return 'c_' + (clientId++).toString(36); @@ -440,10 +436,6 @@ export function prepareScopeUpdate(scopeInstance: Object, inst: Object): void { nodeToInstanceMap.set(scopeInstance, inst); } -export function removeScopeEventHandles(scopeInstance: Object): void { - nodeToInstanceMap.delete(scopeInstance); -} - export function getInstanceFromScope(scopeInstance: Object): null | Object { return nodeToInstanceMap.get(scopeInstance) || null; } diff --git a/scripts/error-codes/codes.json b/scripts/error-codes/codes.json index c777a7c2b2..754f6787be 100644 --- a/scripts/error-codes/codes.json +++ b/scripts/error-codes/codes.json @@ -1,4 +1,3 @@ - { "0": "React.addons.createFragment(...): Encountered an invalid child; DOM elements are not valid children of React components.", "1": "update(): expected target of %s to be an array; got %s.", @@ -366,5 +365,7 @@ "365": "Invalid selector type %s specified.", "366": "ReactDOM.createEventHandle: setListener called on an target that did not have a corresponding root. This is likely a bug in React.", "367": "ReactDOM.createEventHandle: setListener called on an element target that is not managed by React. Ensure React rendered the DOM element.", - "368": "ReactDOM.createEventHandle: setListener called on an invalid target. Provide a valid EventTarget or an element managed by React." + "368": "ReactDOM.createEventHandle: setListener called on an invalid target. Provide a valid EventTarget or an element managed by React.", + "369": "ReactDOM.createEventHandle: setter called on an invalid target. Provide a valid EventTarget or an element managed by React.", + "370": "ReactDOM.createEventHandle: setter called with an invalid callback. The callback must be a function." }