React DOM event handle
一、作用
二、创建事件处理器
备注
allNativeEvents由 EventRegistry#allNativeEvents 提供doesTargetHaveEventHandle()由 ReactDOMComponentTree#doesTargetHaveEventHandle 实现addEventHandleToTarget()由 ReactDOMComponentTree#addEventHandleToTarget 实现getEventHandlerListeners()由 ReactDOMComponentTree#getEventHandlerListeners 实现setEventHandlerListeners()由 ReactDOMComponentTree#setEventHandlerListeners 实现
export function createEventHandle(
type: string,
options?: EventHandleOptions,
): ReactDOMEventHandle {
if (enableCreateEventHandleAPI) {
const domEventName = type as any as DOMEventName;
// We cannot support arbitrary native events with eager root listeners
// because the eager strategy relies on knowing the whole list ahead of time.
// If we wanted to support this, we'd have to add code to keep track
// (or search) for all portal and root containers, and lazily add listeners
// to them whenever we see a previously unknown event. This seems like a lot
// of complexity for something we don't even have a particular use case for.
// Unfortunately, the downside of this invariant is that *removing* a native
// event from the list of known events has now become a breaking change for
// any code relying on the createEventHandle API.
// 我们无法通过急切根监听器支持任意的原生事件,因为急切策略依赖于预先知道完整的事件列表。如果我
// 们想支持这一点,就必须添加代码来跟踪(或搜索)所有的门户和根容器,并在看到以前未知的事件时懒
// 惰地向它们添加监听器。对于我们甚至没有具体使用案例的事情来说,这似乎增加了很多复杂性。不幸的
// 是,这个不变量的一个缺点是,从已知事件列表中*移除*原生事件现在已经成为依赖
// `createEventHandle` API 的任何代码的破坏性更改。
if (!allNativeEvents.has(domEventName)) {
throw new Error(
`Cannot call unstable_createEventHandle with "${domEventName}", as it is not an event known to React.`,
);
}
let isCapturePhaseListener = false;
if (options != null) {
const optionsCapture = options.capture;
if (typeof optionsCapture === 'boolean') {
isCapturePhaseListener = optionsCapture;
}
}
const eventHandle: ReactDOMEventHandle = (
target: EventTarget | ReactScopeInstance,
callback: (syntheticEvent: SyntheticEvent) => void,
) => {
if (typeof callback !== 'function') {
throw new Error(
'ReactDOM.createEventHandle: setter called with an invalid ' +
'callback. The callback must be a function.',
);
}
if (!doesTargetHaveEventHandle(target, eventHandle)) {
addEventHandleToTarget(target, eventHandle);
registerReactDOMEvent(target, domEventName, isCapturePhaseListener);
}
const listener = createEventHandleListener(
domEventName,
isCapturePhaseListener,
callback,
);
let targetListeners = getEventHandlerListeners(target);
if (targetListeners === null) {
targetListeners = new Set();
setEventHandlerListeners(target, targetListeners);
}
targetListeners.add(listener);
return () => {
(targetListeners as any as Set<ReactDOMEventHandleListener>).delete(
listener,
);
};
};
return eventHandle;
}
return null as any;
}
三、工具
1. 是有效的事件目标
function isValidEventTarget(target: EventTarget | ReactScopeInstance): boolean {
return typeof (target as Object).addEventListener === 'function';
}
2. 是 React 范围
function isReactScope(target: EventTarget | ReactScopeInstance): boolean {
return typeof (target as Object).getChildContextValues === 'function';
}
3. 创建事件处理监听器
function createEventHandleListener(
type: DOMEventName,
isCapturePhaseListener: boolean,
callback: (syntheticEvent: SyntheticEvent) => void,
): ReactDOMEventHandleListener {
return {
callback,
capture: isCapturePhaseListener,
type,
};
}
4. 注册 React DOM 事件
备注
ELEMENT_NODE由 HTMLNodeType#ELEMENT_NODE 提供enableScopeAPI()由 ReactFeatureFlags#enableScopeAPI 实现listenToNativeEventForNonManagedEventTarget()由 DOMPluginEventSystem#listenToNativeEventForNonManagedEventTarget 实现
function registerReactDOMEvent(
target: EventTarget | ReactScopeInstance,
domEventName: DOMEventName,
isCapturePhaseListener: boolean,
): void {
if ((target as any).nodeType === ELEMENT_NODE) {
// Do nothing. We already attached all root listeners.
// 什么也不做。我们已经附加了所有根监听器。
} else if (enableScopeAPI && isReactScope(target)) {
// Do nothing. We already attached all root listeners.
// 什么也不做。我们已经附加了所有根监听器。
} else if (isValidEventTarget(target)) {
const eventTarget = target as any as EventTarget;
// These are valid event targets, but they are also
// non-managed React nodes.
// 这些是有效的事件目标,但它们也是非受控的 React 节点。
listenToNativeEventForNonManagedEventTarget(
domEventName,
isCapturePhaseListener,
eventTarget,
);
} else {
throw new Error(
'ReactDOM.createEventHandle: setter called on an invalid ' +
'target. Provide a valid EventTarget or an element managed by React.',
);
}
}
四、类型
1. 事件处理选项
type EventHandleOptions = {
capture?: boolean;
};