Skip to content

Remove ReactDOM.useEvent and associated types+tests #18689

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions packages/react-art/src/ReactARTHostConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -493,22 +493,6 @@ export function makeServerId(): OpaqueIDType {
throw new Error('Not yet implemented');
}

export function registerEvent(event: any, rootContainerInstance: any) {
throw new Error('Not yet implemented.');
}

export function mountEventListener(listener: any) {
throw new Error('Not yet implemented.');
}

export function unmountEventListener(listener: any) {
throw new Error('Not yet implemented.');
}

export function validateEventListenerTarget(target: any, listener: any) {
throw new Error('Not yet implemented.');
}

export function beforeActiveInstanceBlur() {
// noop
}
Expand Down
20 changes: 0 additions & 20 deletions packages/react-debug-tools/src/ReactDebugHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import type {
ReactProviderType,
ReactEventResponder,
ReactEventResponderListener,
ReactScopeMethods,
} from 'shared/ReactTypes';
import type {
Fiber,
Expand Down Expand Up @@ -48,14 +47,6 @@ type HookLogEntry = {
...
};

type ReactDebugListenerMap = {|
clear: () => void,
setListener: (
target: EventTarget | ReactScopeMethods,
callback: ?(SyntheticEvent<EventTarget>) => void,
) => void,
|};

let hookLog: Array<HookLogEntry> = [];

// Primitives
Expand Down Expand Up @@ -311,16 +302,6 @@ function useTransition(
return [callback => {}, false];
}

const noOp = () => {};

function useEvent(event: any): ReactDebugListenerMap {
hookLog.push({primitive: 'Event', stackError: new Error(), value: event});
return {
clear: noOp,
setListener: noOp,
};
}

function useDeferredValue<T>(value: T, config: TimeoutConfig | null | void): T {
// useDeferredValue() composes multiple hooks internally.
// Advance the current hook index the same number of times
Expand Down Expand Up @@ -368,7 +349,6 @@ const Dispatcher: DispatcherType = {
useTransition,
useMutableSource,
useDeferredValue,
useEvent,
useOpaqueIdentifier,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,14 @@
'use strict';

let React;
let ReactDOM;
let ReactDebugTools;

describe('ReactHooksInspection', () => {
beforeEach(() => {
jest.resetModules();
const ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.enableDeprecatedFlareAPI = true;
ReactFeatureFlags.enableUseEventAPI = true;
React = require('react');
ReactDOM = require('react-dom');
ReactDebugTools = require('react-debug-tools');
});

Expand All @@ -46,45 +43,4 @@ describe('ReactHooksInspection', () => {
},
]);
});

// @gate experimental
it('should inspect a simple ReactDOM.useEvent hook', () => {
let clickHandle;
let ref;

const effect = () => {
clickHandle.setListener(ref.current, () => {});
};

function Foo(props) {
ref = React.useRef(null);
clickHandle = ReactDOM.unstable_useEvent('click');
React.useEffect(effect);
return <div ref={ref}>Hello world</div>;
}
const tree = ReactDebugTools.inspectHooks(Foo, {});
expect(tree).toEqual([
{
isStateEditable: false,
id: 0,
name: 'Ref',
subHooks: [],
value: null,
},
{
isStateEditable: false,
id: 1,
name: 'Event',
value: {capture: false, passive: undefined, priority: 0, type: 'click'},
subHooks: [],
},
{
isStateEditable: false,
id: 2,
name: 'Effect',
value: effect,
subHooks: [],
},
]);
});
});
1 change: 0 additions & 1 deletion packages/react-dom/index.classic.fb.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,4 @@ export {
unstable_scheduleHydration,
unstable_renderSubtreeIntoContainer,
unstable_createPortal,
unstable_useEvent,
} from './src/client/ReactDOM';
1 change: 0 additions & 1 deletion packages/react-dom/index.modern.fb.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,4 @@ export {
unstable_flushDiscreteUpdates,
unstable_flushControlled,
unstable_scheduleHydration,
unstable_useEvent,
} from './src/client/ReactDOM';
3 changes: 0 additions & 3 deletions packages/react-dom/src/client/ReactDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
unmountComponentAtNode,
} from './ReactDOMLegacy';
import {createRoot, createBlockingRoot, isValidContainer} from './ReactDOMRoot';
import {useEvent} from './ReactDOMUseEvent';

import {
batchedEventUpdates,
Expand Down Expand Up @@ -211,8 +210,6 @@ export {
// Temporary alias since we already shipped React 16 RC with it.
// TODO: remove in React 17.
unstable_createPortal,
// enableUseEventAPI
useEvent as unstable_useEvent,
};

const foundDevTools = injectIntoDevTools({
Expand Down
17 changes: 0 additions & 17 deletions packages/react-dom/src/client/ReactDOMComponentTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import type {
SuspenseInstance,
Props,
} from './ReactDOMHostConfig';
import type {ReactDOMListener} from '../shared/ReactDOMTypes';

import {
HostComponent,
Expand All @@ -33,7 +32,6 @@ const randomKey = Math.random()
const internalInstanceKey = '__reactFiber$' + randomKey;
const internalEventHandlersKey = '__reactEvents$' + randomKey;
const internalContainerInstanceKey = '__reactContainer$' + randomKey;
const internalEventListenersKey = '__reactListeners$' + randomKey;

export function precacheFiberNode(
hostInst: Fiber,
Expand Down Expand Up @@ -187,18 +185,3 @@ export function updateFiberProps(
): void {
(node: any)[internalEventHandlersKey] = props;
}

// This is used for useEvent listeners
export function getListenersFromTarget(
target: EventTarget,
): null | Set<ReactDOMListener> {
return (target: any)[internalEventListenersKey] || null;
}

// This is used for useEvent listeners
export function initListenersSet(
target: EventTarget,
value: Set<ReactDOMListener>,
): void {
(target: any)[internalEventListenersKey] = value;
}
132 changes: 7 additions & 125 deletions packages/react-dom/src/client/ReactDOMHostConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,12 @@ import type {
ReactDOMEventResponder,
ReactDOMEventResponderInstance,
ReactDOMFundamentalComponentInstance,
ReactDOMListener,
ReactDOMListenerEvent,
ReactDOMListenerMap,
} from '../shared/ReactDOMTypes';
import type {ReactScopeMethods} from 'shared/ReactTypes';

import {
precacheFiberNode,
updateFiberProps,
getClosestInstanceFromNode,
getListenersFromTarget,
} from './ReactDOMComponentTree';
import {
createElement,
Expand Down Expand Up @@ -69,32 +64,9 @@ import {
enableSuspenseServerRenderer,
enableDeprecatedFlareAPI,
enableFundamentalAPI,
enableUseEventAPI,
enableScopeAPI,
} from 'shared/ReactFeatureFlags';
import {
PLUGIN_EVENT_SYSTEM,
USE_EVENT_SYSTEM,
} from '../events/EventSystemFlags';
import {
isManagedDOMElement,
isValidEventTarget,
listenToTopLevelEvent,
attachListenerToManagedDOMElement,
detachListenerFromManagedDOMElement,
attachTargetEventListener,
detachTargetEventListener,
isReactScope,
attachListenerToReactScope,
detachListenerFromReactScope,
} from '../events/DOMModernPluginEventSystem';
import {getListenerMapForElement} from '../events/DOMEventListenerMap';
import {TOP_BEFORE_BLUR, TOP_AFTER_BLUR} from '../events/DOMTopLevelEventTypes';

export type ReactListenerEvent = ReactDOMListenerEvent;
export type ReactListenerMap = ReactDOMListenerMap;
export type ReactListener = ReactDOMListener;

export type Type = string;
export type Props = {
autoFocus?: boolean,
Expand Down Expand Up @@ -246,7 +218,7 @@ export function prepareForCommit(containerInfo: Container): Object | null {
eventsEnabled = ReactBrowserEventEmitterIsEnabled();
selectionInformation = getSelectionInformation();
let activeInstance = null;
if (enableDeprecatedFlareAPI || enableUseEventAPI) {
if (enableDeprecatedFlareAPI) {
const focusedElem = selectionInformation.focusedElem;
if (focusedElem !== null) {
activeInstance = getClosestInstanceFromNode(focusedElem);
Expand All @@ -257,15 +229,15 @@ export function prepareForCommit(containerInfo: Container): Object | null {
}

export function beforeActiveInstanceBlur(): void {
if (enableDeprecatedFlareAPI || enableUseEventAPI) {
if (enableDeprecatedFlareAPI) {
ReactBrowserEventEmitterSetEnabled(true);
dispatchBeforeDetachedBlur((selectionInformation: any).focusedElem);
ReactBrowserEventEmitterSetEnabled(false);
}
}

export function afterActiveInstanceBlur(): void {
if (enableDeprecatedFlareAPI || enableUseEventAPI) {
if (enableDeprecatedFlareAPI) {
ReactBrowserEventEmitterSetEnabled(true);
dispatchAfterDetachedBlur((selectionInformation: any).focusedElem);
ReactBrowserEventEmitterSetEnabled(false);
Expand Down Expand Up @@ -528,7 +500,7 @@ function createEvent(type: TopLevelType): Event {
}

function dispatchBeforeDetachedBlur(target: HTMLElement): void {
if (enableDeprecatedFlareAPI || enableUseEventAPI) {
if (enableDeprecatedFlareAPI) {
const event = createEvent(TOP_BEFORE_BLUR);
// Dispatch "beforeblur" directly on the target,
// so it gets picked up by the event system and
Expand All @@ -538,7 +510,7 @@ function dispatchBeforeDetachedBlur(target: HTMLElement): void {
}

function dispatchAfterDetachedBlur(target: HTMLElement): void {
if (enableDeprecatedFlareAPI || enableUseEventAPI) {
if (enableDeprecatedFlareAPI) {
const event = createEvent(TOP_AFTER_BLUR);
// So we know what was detached, make the relatedTarget the
// detached target on the "afterblur" event.
Expand All @@ -550,23 +522,8 @@ function dispatchAfterDetachedBlur(target: HTMLElement): void {

export function beforeRemoveInstance(
instance: Instance | TextInstance | SuspenseInstance,
): void {
if (enableUseEventAPI) {
// It's unfortunate that we have to do this cleanup, but
// it's necessary otherwise we will leak the host instances
// from the useEvent hook instances Map. We call destroy
// on each listener to ensure we properly remove the instance
// from the instances Map. Note: we have this Map so that we
// can properly unmount instances when the function component
// that the hook is attached to gets unmounted.
const listenersSet = getListenersFromTarget(instance);
if (listenersSet !== null) {
const listeners = Array.from(listenersSet);
for (let i = 0; i < listeners.length; i++) {
listeners[i].destroy(instance);
}
}
}
) {
// TODO for ReactDOM.createEventInstance
}

export function removeChild(
Expand Down Expand Up @@ -1141,78 +1098,3 @@ export function makeOpaqueHydratingObject(
valueOf: attemptToReadValue,
};
}

export function registerEvent(
event: ReactDOMListenerEvent,
rootContainerInstance: Container,
): void {
const {passive, priority, type} = event;
const listenerMap = getListenerMapForElement(rootContainerInstance);
// Add the event listener to the target container (falling back to
// the target if we didn't find one).
listenToTopLevelEvent(
type,
rootContainerInstance,
listenerMap,
PLUGIN_EVENT_SYSTEM | USE_EVENT_SYSTEM,
passive,
priority,
);
}

export function mountEventListener(listener: ReactDOMListener): void {
if (enableUseEventAPI) {
const {target} = listener;
if (isManagedDOMElement(target)) {
attachListenerToManagedDOMElement(listener);
} else if (enableScopeAPI && isReactScope(target)) {
attachListenerToReactScope(listener);
} else {
attachTargetEventListener(listener);
}
}
}

export function unmountEventListener(listener: ReactDOMListener): void {
if (enableUseEventAPI) {
const {target} = listener;
if (isManagedDOMElement(target)) {
detachListenerFromManagedDOMElement(listener);
} else if (enableScopeAPI && isReactScope(target)) {
detachListenerFromReactScope(listener);
} else {
detachTargetEventListener(listener);
}
}
}

export function validateEventListenerTarget(
target: EventTarget | ReactScopeMethods,
listener: ?(SyntheticEvent<EventTarget>) => void,
): boolean {
if (enableUseEventAPI) {
if (
target != null &&
(isManagedDOMElement(target) ||
isValidEventTarget(target) ||
isReactScope(target))
) {
if (listener == null || typeof listener === 'function') {
return true;
}
if (__DEV__) {
console.warn(
'Event listener method setListener() from useEvent() hook requires the second argument' +
' to be either a valid function callback or null/undefined.',
);
}
}
if (__DEV__) {
console.warn(
'Event listener method setListener() from useEvent() hook requires the first argument to be ' +
'a valid DOM EventTarget. If using a ref, ensure the current value is not null.',
);
}
}
return false;
}
Loading