Skip to content
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

Revert useEvent PRs #18438

Merged
merged 2 commits into from Mar 31, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 1 addition & 5 deletions packages/react-debug-tools/src/ReactDebugHooks.js
Expand Up @@ -15,7 +15,6 @@ import type {
ReactProviderType,
ReactEventResponder,
ReactEventResponderListener,
ReactScopeMethods,
} from 'shared/ReactTypes';
import type {Fiber} from 'react-reconciler/src/ReactFiber';
import type {Hook, TimeoutConfig} from 'react-reconciler/src/ReactFiberHooks';
Expand Down Expand Up @@ -45,10 +44,7 @@ type HookLogEntry = {

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

let hookLog: Array<HookLogEntry> = [];
Expand Down
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 Down Expand Up @@ -50,44 +47,4 @@ describe('ReactHooksInspection', () => {
},
]);
});

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>;
}
let 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: [],
},
]);
});
});
4 changes: 0 additions & 4 deletions packages/react-dom/src/client/ReactDOMComponent.js
Expand Up @@ -1348,10 +1348,6 @@ export function listenToEventResponderEventTypes(
const targetEventType = isPassive
? eventType
: eventType.substring(0, eventType.length - 7);
// We don't listen to this as we actually emulate it in the host config
if (targetEventType === 'beforeblur') {
continue;
}
if (!listenerMap.has(eventKey)) {
if (isPassive) {
const activeKey = targetEventType + '_active';
Expand Down
37 changes: 13 additions & 24 deletions packages/react-dom/src/client/ReactDOMHostConfig.js
Expand Up @@ -9,15 +9,6 @@

import type {TopLevelType} from 'legacy-events/TopLevelEventTypes';
import type {RootType} from './ReactDOMRoot';
import type {
ReactDOMEventResponder,
ReactDOMEventResponderInstance,
ReactDOMFundamentalComponentInstance,
ReactDOMListener,
ReactDOMListenerEvent,
ReactDOMListenerMap,
} from '../shared/ReactDOMTypes';
import type {ReactScopeMethods} from 'shared/ReactTypes';

import {
precacheFiberNode,
Expand Down Expand Up @@ -58,6 +49,14 @@ import {
} from '../shared/HTMLNodeType';
import dangerousStyleValue from '../shared/dangerousStyleValue';

import type {
ReactDOMEventResponder,
ReactDOMEventResponderInstance,
ReactDOMFundamentalComponentInstance,
ReactDOMListener,
ReactDOMListenerEvent,
ReactDOMListenerMap,
} from '../shared/ReactDOMTypes';
import {
mountEventResponder,
unmountEventResponder,
Expand All @@ -70,7 +69,6 @@ import {
enableDeprecatedFlareAPI,
enableFundamentalAPI,
enableUseEventAPI,
enableScopeAPI,
} from 'shared/ReactFeatureFlags';
import {HostComponent} from 'react-reconciler/src/ReactWorkTags';
import {
Expand All @@ -81,13 +79,10 @@ import {
isManagedDOMElement,
isValidEventTarget,
listenToTopLevelEvent,
attachListenerToManagedDOMElement,
detachListenerFromManagedDOMElement,
attachTargetEventListener,
attachListenerFromManagedDOMElement,
detachTargetEventListener,
isReactScope,
attachListenerToReactScope,
detachListenerFromReactScope,
attachTargetEventListener,
} from '../events/DOMModernPluginEventSystem';
import {getListenerMapForElement} from '../events/DOMEventListenerMap';
import {TOP_BEFORE_BLUR, TOP_AFTER_BLUR} from '../events/DOMTopLevelEventTypes';
Expand Down Expand Up @@ -1165,9 +1160,7 @@ export function mountEventListener(listener: ReactDOMListener): void {
if (enableUseEventAPI) {
const {target} = listener;
if (isManagedDOMElement(target)) {
attachListenerToManagedDOMElement(listener);
} else if (enableScopeAPI && isReactScope(target)) {
attachListenerToReactScope(listener);
attachListenerFromManagedDOMElement(listener);
} else {
attachTargetEventListener(listener);
}
Expand All @@ -1179,24 +1172,20 @@ export function unmountEventListener(listener: ReactDOMListener): void {
const {target} = listener;
if (isManagedDOMElement(target)) {
detachListenerFromManagedDOMElement(listener);
} else if (enableScopeAPI && isReactScope(target)) {
detachListenerFromReactScope(listener);
} else {
detachTargetEventListener(listener);
}
}
}

export function validateEventListenerTarget(
target: EventTarget | ReactScopeMethods,
target: EventTarget,
listener: ?(Event) => void,
): boolean {
if (enableUseEventAPI) {
if (
target != null &&
(isManagedDOMElement(target) ||
isValidEventTarget(target) ||
isReactScope(target))
(isManagedDOMElement(target) || isValidEventTarget(target))
) {
if (listener == null || typeof listener === 'function') {
return true;
Expand Down
115 changes: 22 additions & 93 deletions packages/react-dom/src/events/DOMModernPluginEventSystem.js
Expand Up @@ -14,7 +14,7 @@ import type {
ElementListenerMapEntry,
} from '../events/DOMEventListenerMap';
import type {EventSystemFlags} from 'legacy-events/EventSystemFlags';
import type {EventPriority, ReactScopeMethods} from 'shared/ReactTypes';
import type {EventPriority} from 'shared/ReactTypes';
import type {Fiber} from 'react-reconciler/src/ReactFiber';
import type {PluginModule} from 'legacy-events/PluginModuleType';
import type {
Expand Down Expand Up @@ -142,11 +142,8 @@ const emptyDispatchConfigForCustomEvents: CustomDispatchConfig = {

const isArray = Array.isArray;

// TODO: we should remove the FlowFixMes and the casting to figure out how to make
// these patterns work properly.
// $FlowFixMe: Flow struggles with this pattern, so we also have to cast it.
const PossiblyWeakMap = ((typeof WeakMap === 'function' ? WeakMap : Map): any);

// $FlowFixMe: Flow struggles with this pattern
const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;
// $FlowFixMe: Flow cannot handle polymorphic WeakMaps
export const eventTargetEventListenerStore: WeakMap<
EventTarget,
Expand All @@ -156,15 +153,6 @@ export const eventTargetEventListenerStore: WeakMap<
>,
> = new PossiblyWeakMap();

// $FlowFixMe: Flow cannot handle polymorphic WeakMaps
export const reactScopeListenerStore: WeakMap<
ReactScopeMethods,
Map<
DOMTopLevelEventType,
{bubbled: Set<ReactDOMListener>, captured: Set<ReactDOMListener>},
>,
> = new PossiblyWeakMap();

function dispatchEventsForPlugins(
topLevelType: DOMTopLevelEventType,
eventSystemFlags: EventSystemFlags,
Expand Down Expand Up @@ -318,20 +306,12 @@ function isMatchingRootContainer(
);
}

export function isManagedDOMElement(
target: EventTarget | ReactScopeMethods,
): boolean {
export function isManagedDOMElement(target: EventTarget): boolean {
return getClosestInstanceFromNode(((target: any): Node)) !== null;
}

export function isValidEventTarget(
target: EventTarget | ReactScopeMethods,
): boolean {
return typeof (target: Object).addEventListener === 'function';
}

export function isReactScope(target: EventTarget | ReactScopeMethods): boolean {
return typeof (target: Object).getChildContextValues === 'function';
export function isValidEventTarget(target: EventTarget): boolean {
return typeof target.addEventListener === 'function';
}

export function dispatchEventForPluginEventSystem(
Expand Down Expand Up @@ -466,16 +446,18 @@ function addEventTypeToDispatchConfig(type: DOMTopLevelEventType): void {
}
}

export function attachListenerToManagedDOMElement(
export function attachListenerFromManagedDOMElement(
listener: ReactDOMListener,
): void {
const {event, target} = listener;
const {passive, priority, type} = event;

const managedTargetElement = ((target: any): Element);
const containerEventTarget = getNearestRootOrPortalContainer(
managedTargetElement,
);
const possibleManagedTarget = ((target: any): Element);
let containerEventTarget = target;
if (getClosestInstanceFromNode(possibleManagedTarget)) {
containerEventTarget = getNearestRootOrPortalContainer(
possibleManagedTarget,
);
}
const listenerMap = getListenerMapForElement(containerEventTarget);
// Add the event listener to the target container (falling back to
// the target if we didn't find one).
Expand All @@ -487,11 +469,11 @@ export function attachListenerToManagedDOMElement(
priority,
);
// Get the internal listeners Set from the target instance.
let listeners = getListenersFromTarget(managedTargetElement);
let listeners = getListenersFromTarget(target);
// If we don't have any listeners, then we need to init them.
if (listeners === null) {
listeners = new Set();
initListenersSet(managedTargetElement, listeners);
initListenersSet(target, listeners);
}
// Add our listener to the listeners Set.
listeners.add(listener);
Expand All @@ -503,9 +485,8 @@ export function detachListenerFromManagedDOMElement(
listener: ReactDOMListener,
): void {
const {target} = listener;
const managedTargetElement = ((target: any): Element);
// Get the internal listeners Set from the target instance.
const listeners = getListenersFromTarget(managedTargetElement);
const listeners = getListenersFromTarget(target);
if (listeners !== null) {
// Remove out listener from the listeners Set.
listeners.delete(listener);
Expand All @@ -515,21 +496,13 @@ export function detachListenerFromManagedDOMElement(
export function attachTargetEventListener(listener: ReactDOMListener): void {
const {event, target} = listener;
const {capture, passive, priority, type} = event;
const eventTarget = ((target: any): EventTarget);
const listenerMap = getListenerMapForElement(eventTarget);
const listenerMap = getListenerMapForElement(target);
// Add the event listener to the TargetEvent object.
listenToTopLevelEvent(
type,
eventTarget,
listenerMap,
passive,
priority,
capture,
);
let eventTypeMap = eventTargetEventListenerStore.get(eventTarget);
listenToTopLevelEvent(type, target, listenerMap, passive, priority, capture);
let eventTypeMap = eventTargetEventListenerStore.get(target);
if (eventTypeMap === undefined) {
eventTypeMap = new Map();
eventTargetEventListenerStore.set(eventTarget, eventTypeMap);
eventTargetEventListenerStore.set(target, eventTypeMap);
}
// Get the listeners by the event type
let listeners = eventTypeMap.get(type);
Expand All @@ -550,51 +523,7 @@ export function attachTargetEventListener(listener: ReactDOMListener): void {
export function detachTargetEventListener(listener: ReactDOMListener): void {
const {event, target} = listener;
const {capture, type} = event;
const validEventTarget = ((target: any): EventTarget);
const eventTypeMap = eventTargetEventListenerStore.get(validEventTarget);
if (eventTypeMap !== undefined) {
const listeners = eventTypeMap.get(type);
if (listeners !== undefined) {
// Remove out listener from the listeners Set.
if (capture) {
listeners.captured.delete(listener);
} else {
listeners.bubbled.delete(listener);
}
}
}
}

export function attachListenerToReactScope(listener: ReactDOMListener): void {
const {event, target} = listener;
const {capture, type} = event;
const reactScope = ((target: any): ReactScopeMethods);
let eventTypeMap = reactScopeListenerStore.get(reactScope);
if (eventTypeMap === undefined) {
eventTypeMap = new Map();
reactScopeListenerStore.set(reactScope, eventTypeMap);
}
// Get the listeners by the event type
let listeners = eventTypeMap.get(type);
if (listeners === undefined) {
listeners = {captured: new Set(), bubbled: new Set()};
eventTypeMap.set(type, listeners);
}
// Add our listener to the listeners Set.
if (capture) {
listeners.captured.add(listener);
} else {
listeners.bubbled.add(listener);
}
// Finally, add the event to our known event types list.
addEventTypeToDispatchConfig(type);
}

export function detachListenerFromReactScope(listener: ReactDOMListener): void {
const {event, target} = listener;
const {capture, type} = event;
const reactScope = ((target: any): ReactScopeMethods);
const eventTypeMap = reactScopeListenerStore.get(reactScope);
const eventTypeMap = eventTargetEventListenerStore.get(target);
if (eventTypeMap !== undefined) {
const listeners = eventTypeMap.get(type);
if (listeners !== undefined) {
Expand Down