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

Add infrastructure for passive/non-passive event support for future API exploration #15036

Merged
merged 20 commits into from
Mar 15, 2019
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
16 changes: 16 additions & 0 deletions packages/events/EventSystemFlags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

export type EventSystemFlags = number;

export const PLUGIN_EVENT_SYSTEM = 1;
export const RESPONDER_EVENT_SYSTEM = 1 << 1;
export const IS_PASSIVE = 1 << 2;
export const IS_ACTIVE = 1 << 3;
export const PASSIVE_NOT_SUPPORTED = 1 << 4;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why we don't use literal number(and add comment) here just like maxSigned31BitInt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are used to do bitwise operations on, as there can be a combination of the above being used.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the question was why 1 << 4 is used over 16. 1 << 4 makes the intent clearer. maxSigned31BitInt "solves" this by adding a comment. I don't think it matters what pattern is used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea, just like @eps1lon said

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pattern is clear, as we may add more in the future, which is simply 1 << 5, 1 << 6 etc. We use this approach throughout the React codebase and we've verified that Google Closure Compiler simplifies the constant value.

8 changes: 4 additions & 4 deletions packages/events/ReactGenericBatching.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import {
let _batchedUpdatesImpl = function(fn, bookkeeping) {
return fn(bookkeeping);
};
let _interactiveUpdatesImpl = function(fn, a, b) {
return fn(a, b);
let _interactiveUpdatesImpl = function(fn, a, b, c) {
return fn(a, b, c);
};
let _flushInteractiveUpdatesImpl = function() {};

Expand Down Expand Up @@ -52,8 +52,8 @@ export function batchedUpdates(fn, bookkeeping) {
}
}

export function interactiveUpdates(fn, a, b) {
return _interactiveUpdatesImpl(fn, a, b);
export function interactiveUpdates(fn, a, b, c) {
return _interactiveUpdatesImpl(fn, a, b, c);
}

export function flushInteractiveUpdates() {
Expand Down
5 changes: 4 additions & 1 deletion packages/react-dom/src/client/ReactDOMComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,10 @@ if (__DEV__) {
};
}

function ensureListeningTo(rootContainerElement, registrationName) {
function ensureListeningTo(
rootContainerElement: Element | Node,
registrationName: string,
): void {
const isDocumentOrFragment =
rootContainerElement.nodeType === DOCUMENT_NODE ||
rootContainerElement.nodeType === DOCUMENT_FRAGMENT_NODE;
Expand Down
13 changes: 11 additions & 2 deletions packages/react-dom/src/events/EventListener.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,26 @@
*/

export function addEventBubbleListener(
element: Document | Element,
element: Document | Element | Node,
eventType: string,
listener: Function,
): void {
element.addEventListener(eventType, listener, false);
}

export function addEventCaptureListener(
element: Document | Element,
element: Document | Element | Node,
eventType: string,
listener: Function,
): void {
element.addEventListener(eventType, listener, true);
}

export function addEventListener(
element: Document | Element | Node,
eventType: string,
listener: Function,
options: {passive: boolean},
): void {
element.addEventListener(eventType, listener, (options: any));
}
51 changes: 27 additions & 24 deletions packages/react-dom/src/events/ReactBrowserEventEmitter.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

import {registrationNameDependencies} from 'events/EventPluginRegistry';
import type {DOMTopLevelEventType} from 'events/TopLevelEventTypes';
import {
TOP_BLUR,
TOP_CANCEL,
Expand Down Expand Up @@ -84,22 +85,23 @@ import isEventSupported from './isEventSupported';
* React Core . General Purpose Event Plugin System
*/

const alreadyListeningTo = {};
let reactTopListenersCounter = 0;
const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;
const elementListeningSets:
| WeakMap
| Map<
Document | Element | Node,
Set<DOMTopLevelEventType>,
> = new PossiblyWeakMap();
trueadm marked this conversation as resolved.
Show resolved Hide resolved

/**
* To ensure no conflicts with other potential React instances on the page
*/
const topListenersIDKey = '_reactListenersID' + ('' + Math.random()).slice(2);

function getListeningForDocument(mountAt: any) {
// In IE8, `mountAt` is a host object and doesn't have `hasOwnProperty`
// directly.
if (!Object.prototype.hasOwnProperty.call(mountAt, topListenersIDKey)) {
mountAt[topListenersIDKey] = reactTopListenersCounter++;
alreadyListeningTo[mountAt[topListenersIDKey]] = {};
function getListeningSetForElement(
element: Document | Element | Node,
): Set<DOMTopLevelEventType> {
let listeningSet = elementListeningSets.get(element);
if (listeningSet === undefined) {
listeningSet = new Set();
elementListeningSets.set(element, listeningSet);
}
return alreadyListeningTo[mountAt[topListenersIDKey]];
return listeningSet;
}

/**
Expand All @@ -125,14 +127,14 @@ function getListeningForDocument(mountAt: any) {
*/
export function listenTo(
registrationName: string,
mountAt: Document | Element,
) {
const isListening = getListeningForDocument(mountAt);
mountAt: Document | Element | Node,
): void {
trueadm marked this conversation as resolved.
Show resolved Hide resolved
const listeningSet = getListeningSetForElement(mountAt);
const dependencies = registrationNameDependencies[registrationName];

for (let i = 0; i < dependencies.length; i++) {
const dependency = dependencies[i];
if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) {
if (!listeningSet.has(dependency)) {
switch (dependency) {
case TOP_SCROLL:
trapCapturedEvent(TOP_SCROLL, mountAt);
Expand All @@ -143,8 +145,8 @@ export function listenTo(
trapCapturedEvent(TOP_BLUR, mountAt);
// We set the flag for a single dependency later in this function,
// but this ensures we mark both as attached rather than just one.
isListening[TOP_BLUR] = true;
isListening[TOP_FOCUS] = true;
listeningSet.add(TOP_BLUR);
listeningSet.add(TOP_FOCUS);
break;
case TOP_CANCEL:
case TOP_CLOSE:
Expand All @@ -167,20 +169,21 @@ export function listenTo(
}
break;
}
isListening[dependency] = true;
listeningSet.add(dependency);
}
}
}

export function isListeningToAllDependencies(
registrationName: string,
mountAt: Document | Element,
) {
const isListening = getListeningForDocument(mountAt);
): boolean {
const listeningSet = getListeningSetForElement(mountAt);
const dependencies = registrationNameDependencies[registrationName];

for (let i = 0; i < dependencies.length; i++) {
const dependency = dependencies[i];
if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) {
if (!listeningSet.has(dependency)) {
return false;
}
}
Expand Down