Enable eager listeners statically (#19983)

This commit is contained in:
Dan Abramov
2020-10-08 19:32:28 +01:00
committed by GitHub
parent 40c52de960
commit 993ca533b4
21 changed files with 53 additions and 400 deletions
@@ -1040,7 +1040,6 @@ describe('ReactDOMFiber', () => {
expect(ops).toEqual([]);
});
// @gate enableEagerRootListeners
it('listens to events that do not exist in the Portal subtree', () => {
const onClick = jest.fn();
+5 -83
View File
@@ -61,12 +61,7 @@ import {
shouldRemoveAttribute,
} from '../shared/DOMProperty';
import assertValidProps from '../shared/assertValidProps';
import {
DOCUMENT_NODE,
ELEMENT_NODE,
COMMENT_NODE,
DOCUMENT_FRAGMENT_NODE,
} from '../shared/HTMLNodeType';
import {DOCUMENT_NODE} from '../shared/HTMLNodeType';
import isCustomComponent from '../shared/isCustomComponent';
import possibleStandardNames from '../shared/possibleStandardNames';
import {validateProperties as validateARIAProperties} from '../shared/ReactDOMInvalidARIAHook';
@@ -74,12 +69,8 @@ import {validateProperties as validateInputProperties} from '../shared/ReactDOMN
import {validateProperties as validateUnknownProperties} from '../shared/ReactDOMUnknownPropertyHook';
import {REACT_OPAQUE_ID_TYPE} from 'shared/ReactSymbols';
import {enableTrustedTypesIntegration} from 'shared/ReactFeatureFlags';
import {
enableTrustedTypesIntegration,
enableEagerRootListeners,
} from 'shared/ReactFeatureFlags';
import {
listenToReactEvent,
mediaEventTypes,
listenToNonDelegatedEvent,
} from '../events/DOMPluginEventSystem';
@@ -253,39 +244,6 @@ if (__DEV__) {
};
}
export function ensureListeningTo(
rootContainerInstance: Element | Node,
reactPropEvent: string,
targetElement: Element | null,
): void {
if (!enableEagerRootListeners) {
// If we have a comment node, then use the parent node,
// which should be an element.
const rootContainerElement =
rootContainerInstance.nodeType === COMMENT_NODE
? rootContainerInstance.parentNode
: rootContainerInstance;
if (__DEV__) {
if (
rootContainerElement == null ||
(rootContainerElement.nodeType !== ELEMENT_NODE &&
// This is to support rendering into a ShadowRoot:
rootContainerElement.nodeType !== DOCUMENT_FRAGMENT_NODE)
) {
console.error(
'ensureListeningTo(): received a container that was not an element node. ' +
'This is likely a bug in React. Please file an issue.',
);
}
}
listenToReactEvent(
reactPropEvent,
((rootContainerElement: any): Element),
targetElement,
);
}
}
function getOwnerDocumentFromRootContainer(
rootContainerElement: Element | Document,
): Document {
@@ -364,9 +322,7 @@ function setInitialDOMProperties(
if (__DEV__ && typeof nextProp !== 'function') {
warnForInvalidEventListener(propKey, nextProp);
}
if (!enableEagerRootListeners) {
ensureListeningTo(rootContainerElement, propKey, domElement);
} else if (propKey === 'onScroll') {
if (propKey === 'onScroll') {
listenToNonDelegatedEvent('scroll', domElement);
}
}
@@ -577,11 +533,6 @@ export function setInitialProperties(
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the invalid event.
listenToNonDelegatedEvent('invalid', domElement);
if (!enableEagerRootListeners) {
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange', domElement);
}
break;
case 'option':
ReactDOMOptionValidateProps(domElement, rawProps);
@@ -593,11 +544,6 @@ export function setInitialProperties(
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the invalid event.
listenToNonDelegatedEvent('invalid', domElement);
if (!enableEagerRootListeners) {
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange', domElement);
}
break;
case 'textarea':
ReactDOMTextareaInitWrapperState(domElement, rawProps);
@@ -605,11 +551,6 @@ export function setInitialProperties(
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the invalid event.
listenToNonDelegatedEvent('invalid', domElement);
if (!enableEagerRootListeners) {
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange', domElement);
}
break;
default:
props = rawProps;
@@ -827,9 +768,7 @@ export function diffProperties(
if (__DEV__ && typeof nextProp !== 'function') {
warnForInvalidEventListener(propKey, nextProp);
}
if (!enableEagerRootListeners) {
ensureListeningTo(rootContainerElement, propKey, domElement);
} else if (propKey === 'onScroll') {
if (propKey === 'onScroll') {
listenToNonDelegatedEvent('scroll', domElement);
}
}
@@ -983,11 +922,6 @@ export function diffHydratedProperties(
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the invalid event.
listenToNonDelegatedEvent('invalid', domElement);
if (!enableEagerRootListeners) {
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange', domElement);
}
break;
case 'option':
ReactDOMOptionValidateProps(domElement, rawProps);
@@ -997,22 +931,12 @@ export function diffHydratedProperties(
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the invalid event.
listenToNonDelegatedEvent('invalid', domElement);
if (!enableEagerRootListeners) {
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange', domElement);
}
break;
case 'textarea':
ReactDOMTextareaInitWrapperState(domElement, rawProps);
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the invalid event.
listenToNonDelegatedEvent('invalid', domElement);
if (!enableEagerRootListeners) {
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange', domElement);
}
break;
}
@@ -1079,9 +1003,7 @@ export function diffHydratedProperties(
if (__DEV__ && typeof nextProp !== 'function') {
warnForInvalidEventListener(propKey, nextProp);
}
if (!enableEagerRootListeners) {
ensureListeningTo(rootContainerElement, propKey, domElement);
} else if (propKey === 'onScroll') {
if (propKey === 'onScroll') {
listenToNonDelegatedEvent('scroll', domElement);
}
}
+3 -84
View File
@@ -16,23 +16,19 @@ import type {
import {allNativeEvents} from '../events/EventRegistry';
import {
getClosestInstanceFromNode,
getEventHandlerListeners,
setEventHandlerListeners,
getFiberFromScopeInstance,
doesTargetHaveEventHandle,
addEventHandleToTarget,
} from './ReactDOMComponentTree';
import {ELEMENT_NODE, COMMENT_NODE} from '../shared/HTMLNodeType';
import {ELEMENT_NODE} from '../shared/HTMLNodeType';
import {listenToNativeEvent} from '../events/DOMPluginEventSystem';
import {HostRoot, HostPortal} from 'react-reconciler/src/ReactWorkTags';
import {IS_EVENT_HANDLE_NON_MANAGED_NODE} from '../events/EventSystemFlags';
import {
enableScopeAPI,
enableCreateEventHandleAPI,
enableEagerRootListeners,
} from 'shared/ReactFeatureFlags';
import invariant from 'shared/invariant';
@@ -40,19 +36,6 @@ type EventHandleOptions = {|
capture?: boolean,
|};
function getNearestRootOrPortalContainer(node: Fiber): null | Element {
while (node !== null) {
const tag = node.tag;
// Once we encounter a host container or root container
// we can return their DOM instance.
if (tag === HostRoot || tag === HostPortal) {
return node.stateNode.containerInfo;
}
node = node.return;
}
return null;
}
function isValidEventTarget(target: EventTarget | ReactScopeInstance): boolean {
return typeof (target: Object).addEventListener === 'function';
}
@@ -73,79 +56,15 @@ function createEventHandleListener(
};
}
function registerEventOnNearestTargetContainer(
targetFiber: Fiber,
domEventName: DOMEventName,
isCapturePhaseListener: boolean,
targetElement: Element | null,
): void {
if (!enableEagerRootListeners) {
// If it is, find the nearest root or portal and make it
// our event handle target container.
let targetContainer = getNearestRootOrPortalContainer(targetFiber);
if (targetContainer === null) {
if (__DEV__) {
console.error(
'ReactDOM.createEventHandle: setListener called on an target ' +
'that did not have a corresponding root. This is likely a bug in React.',
);
}
return;
}
if (targetContainer.nodeType === COMMENT_NODE) {
targetContainer = ((targetContainer.parentNode: any): Element);
}
listenToNativeEvent(
domEventName,
isCapturePhaseListener,
targetContainer,
targetElement,
);
}
}
function registerReactDOMEvent(
target: EventTarget | ReactScopeInstance,
domEventName: DOMEventName,
isCapturePhaseListener: boolean,
): void {
// Check if the target is a DOM element.
if ((target: any).nodeType === ELEMENT_NODE) {
if (!enableEagerRootListeners) {
const targetElement = ((target: any): Element);
// Check if the DOM element is managed by React.
const targetFiber = getClosestInstanceFromNode(targetElement);
if (targetFiber === null) {
if (__DEV__) {
console.error(
'ReactDOM.createEventHandle: setListener called on an element ' +
'target that is not managed by React. Ensure React rendered the DOM element.',
);
}
return;
}
registerEventOnNearestTargetContainer(
targetFiber,
domEventName,
isCapturePhaseListener,
targetElement,
);
}
// Do nothing. We already attached all root listeners.
} else if (enableScopeAPI && isReactScope(target)) {
if (!enableEagerRootListeners) {
const scopeTarget = ((target: any): ReactScopeInstance);
const targetFiber = getFiberFromScopeInstance(scopeTarget);
if (targetFiber === null) {
// Scope is unmounted, do not proceed.
return;
}
registerEventOnNearestTargetContainer(
targetFiber,
domEventName,
isCapturePhaseListener,
null,
);
}
// Do nothing. We already attached all root listeners.
} else if (isValidEventTarget(target)) {
const eventTarget = ((target: any): EventTarget);
// These are valid event targets, but they are also
+2 -10
View File
@@ -67,13 +67,9 @@ import {
enableFundamentalAPI,
enableCreateEventHandleAPI,
enableScopeAPI,
enableEagerRootListeners,
} from 'shared/ReactFeatureFlags';
import {HostComponent, HostText} from 'react-reconciler/src/ReactWorkTags';
import {
listenToReactEvent,
listenToAllSupportedEvents,
} from '../events/DOMPluginEventSystem';
import {listenToAllSupportedEvents} from '../events/DOMPluginEventSystem';
export type Type = string;
export type Props = {
@@ -1073,11 +1069,7 @@ export function makeOpaqueHydratingObject(
}
export function preparePortalMount(portalInstance: Instance): void {
if (enableEagerRootListeners) {
listenToAllSupportedEvents(portalInstance);
} else {
listenToReactEvent('onMouseEnter', portalInstance, null);
}
listenToAllSupportedEvents(portalInstance);
}
export function prepareScopeUpdate(
+3 -26
View File
@@ -36,14 +36,12 @@ import {
unmarkContainerAsRoot,
} from './ReactDOMComponentTree';
import {listenToAllSupportedEvents} from '../events/DOMPluginEventSystem';
import {eagerlyTrapReplayableEvents} from '../events/ReactDOMEventReplaying';
import {
ELEMENT_NODE,
COMMENT_NODE,
DOCUMENT_NODE,
DOCUMENT_FRAGMENT_NODE,
} from '../shared/HTMLNodeType';
import {ensureListeningTo} from './ReactDOMComponent';
import {
createContainer,
@@ -52,7 +50,6 @@ import {
registerMutableSourceForHydration,
} from 'react-reconciler/src/ReactFiberReconciler';
import invariant from 'shared/invariant';
import {enableEagerRootListeners} from 'shared/ReactFeatureFlags';
import {
BlockingRoot,
ConcurrentRoot,
@@ -133,30 +130,10 @@ function createRootImpl(
null;
const root = createContainer(container, tag, hydrate, hydrationCallbacks);
markContainerAsRoot(root.current, container);
const containerNodeType = container.nodeType;
if (enableEagerRootListeners) {
const rootContainerElement =
container.nodeType === COMMENT_NODE ? container.parentNode : container;
listenToAllSupportedEvents(rootContainerElement);
} else {
if (hydrate && tag !== LegacyRoot) {
const doc =
containerNodeType === DOCUMENT_NODE
? container
: container.ownerDocument;
// We need to cast this because Flow doesn't work
// with the hoisted containerNodeType. If we inline
// it, then Flow doesn't complain. We intentionally
// hoist it to reduce code-size.
eagerlyTrapReplayableEvents(container, ((doc: any): Document));
} else if (
containerNodeType !== DOCUMENT_FRAGMENT_NODE &&
containerNodeType !== DOCUMENT_NODE
) {
ensureListeningTo(container, 'onMouseEnter', null);
}
}
const rootContainerElement =
container.nodeType === COMMENT_NODE ? container.parentNode : container;
listenToAllSupportedEvents(rootContainerElement);
if (mutableSources) {
for (let i = 0; i < mutableSources.length; i++) {
+20 -77
View File
@@ -21,7 +21,7 @@ import type {
} from './ReactSyntheticEventType';
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
import {registrationNameDependencies, allNativeEvents} from './EventRegistry';
import {allNativeEvents} from './EventRegistry';
import {
IS_CAPTURE_PHASE,
IS_EVENT_HANDLE_NON_MANAGED_NODE,
@@ -51,7 +51,6 @@ import {
enableLegacyFBSupport,
enableCreateEventHandleAPI,
enableScopeAPI,
enableEagerRootListeners,
} from 'shared/ReactFeatureFlags';
import {
invokeGuardedCallbackAndCatchFirstError,
@@ -320,32 +319,30 @@ const listeningMarker =
.slice(2);
export function listenToAllSupportedEvents(rootContainerElement: EventTarget) {
if (enableEagerRootListeners) {
if ((rootContainerElement: any)[listeningMarker]) {
// Performance optimization: don't iterate through events
// for the same portal container or root node more than once.
// TODO: once we remove the flag, we may be able to also
// remove some of the bookkeeping maps used for laziness.
return;
}
(rootContainerElement: any)[listeningMarker] = true;
allNativeEvents.forEach(domEventName => {
if (!nonDelegatedEvents.has(domEventName)) {
listenToNativeEvent(
domEventName,
false,
((rootContainerElement: any): Element),
null,
);
}
if ((rootContainerElement: any)[listeningMarker]) {
// Performance optimization: don't iterate through events
// for the same portal container or root node more than once.
// TODO: once we remove the flag, we may be able to also
// remove some of the bookkeeping maps used for laziness.
return;
}
(rootContainerElement: any)[listeningMarker] = true;
allNativeEvents.forEach(domEventName => {
if (!nonDelegatedEvents.has(domEventName)) {
listenToNativeEvent(
domEventName,
true,
false,
((rootContainerElement: any): Element),
null,
);
});
}
}
listenToNativeEvent(
domEventName,
true,
((rootContainerElement: any): Element),
null,
);
});
}
export function listenToNativeEvent(
@@ -411,60 +408,6 @@ export function listenToNativeEvent(
}
}
export function listenToReactEvent(
reactEvent: string,
rootContainerElement: Element,
targetElement: Element | null,
): void {
if (!enableEagerRootListeners) {
const dependencies = registrationNameDependencies[reactEvent];
const dependenciesLength = dependencies.length;
// If the dependencies length is 1, that means we're not using a polyfill
// plugin like ChangeEventPlugin, BeforeInputPlugin, EnterLeavePlugin
// and SelectEventPlugin. We always use the native bubble event phase for
// these plugins and emulate two phase event dispatching. SimpleEventPlugin
// always only has a single dependency and SimpleEventPlugin events also
// use either the native capture event phase or bubble event phase, there
// is no emulation (except for focus/blur, but that will be removed soon).
const isPolyfillEventPlugin = dependenciesLength !== 1;
if (isPolyfillEventPlugin) {
const listenerSet = getEventListenerSet(rootContainerElement);
// When eager listeners are off, this Set has a dual purpose: it both
// captures which native listeners we registered (e.g. "click__bubble")
// and *React* lazy listeners (e.g. "onClick") so we don't do extra checks.
// This second usage does not exist in the eager mode.
if (!listenerSet.has(reactEvent)) {
listenerSet.add(reactEvent);
for (let i = 0; i < dependenciesLength; i++) {
listenToNativeEvent(
dependencies[i],
false,
rootContainerElement,
targetElement,
);
}
}
} else {
const isCapturePhaseListener =
reactEvent.substr(-7) === 'Capture' &&
// Edge case: onGotPointerCapture and onLostPointerCapture
// end with "Capture" but that's part of their event names.
// The Capture versions would end with CaptureCapture.
// So we have to check against that.
// This check works because none of the events we support
// end with "Pointer".
reactEvent.substr(-14, 7) !== 'Pointer';
listenToNativeEvent(
dependencies[0],
isCapturePhaseListener,
rootContainerElement,
targetElement,
);
}
}
}
function addTrappedEventListener(
targetContainer: EventTarget,
domEventName: DOMEventName,
+8 -11
View File
@@ -40,7 +40,6 @@ import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
import {
enableLegacyFBSupport,
enableEagerRootListeners,
decoupleUpdatePriorityFromScheduler,
} from 'shared/ReactFeatureFlags';
import {
@@ -188,16 +187,14 @@ export function dispatchEvent(
if (!_enabled) {
return;
}
let allowReplay = true;
if (enableEagerRootListeners) {
// TODO: replaying capture phase events is currently broken
// because we used to do it during top-level native bubble handlers
// but now we use different bubble and capture handlers.
// In eager mode, we attach capture listeners early, so we need
// to filter them out until we fix the logic to handle them correctly.
// This could've been outside the flag but I put it inside to reduce risk.
allowReplay = (eventSystemFlags & IS_CAPTURE_PHASE) === 0;
}
// TODO: replaying capture phase events is currently broken
// because we used to do it during top-level native bubble handlers
// but now we use different bubble and capture handlers.
// In eager mode, we attach capture listeners early, so we need
// to filter them out until we fix the logic to handle them correctly.
const allowReplay = (eventSystemFlags & IS_CAPTURE_PHASE) === 0;
if (
allowReplay &&
hasQueuedDiscreteEvents() &&
+1 -45
View File
@@ -14,10 +14,7 @@ import type {EventSystemFlags} from './EventSystemFlags';
import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
import type {LanePriority} from 'react-reconciler/src/ReactFiberLane';
import {
enableSelectiveHydration,
enableEagerRootListeners,
} from 'shared/ReactFeatureFlags';
import {enableSelectiveHydration} from 'shared/ReactFeatureFlags';
import {
unstable_runWithPriority as runWithPriority,
unstable_scheduleCallback as scheduleCallback,
@@ -85,7 +82,6 @@ type PointerEvent = Event & {
};
import {IS_REPLAYED} from './EventSystemFlags';
import {listenToNativeEvent} from './DOMPluginEventSystem';
type QueuedReplayableEvent = {|
blockedOn: null | Container | SuspenseInstance,
@@ -159,50 +155,10 @@ const discreteReplayableEvents: Array<DOMEventName> = [
'submit',
];
const continuousReplayableEvents: Array<DOMEventName> = [
'dragenter',
'dragleave',
'focusin',
'focusout',
'mouseover',
'mouseout',
'pointerover',
'pointerout',
'gotpointercapture',
'lostpointercapture',
];
export function isReplayableDiscreteEvent(eventType: DOMEventName): boolean {
return discreteReplayableEvents.indexOf(eventType) > -1;
}
function trapReplayableEventForContainer(
domEventName: DOMEventName,
container: Container,
) {
// When the flag is on, we do this in a unified codepath elsewhere.
if (!enableEagerRootListeners) {
listenToNativeEvent(domEventName, false, ((container: any): Element), null);
}
}
export function eagerlyTrapReplayableEvents(
container: Container,
document: Document,
) {
// When the flag is on, we do this in a unified codepath elsewhere.
if (!enableEagerRootListeners) {
// Discrete
discreteReplayableEvents.forEach(domEventName => {
trapReplayableEventForContainer(domEventName, container);
});
// Continuous
continuousReplayableEvents.forEach(domEventName => {
trapReplayableEventForContainer(domEventName, container);
});
}
}
function createQueuedReplayableEvent(
blockedOn: null | Container | SuspenseInstance,
domEventName: DOMEventName,
@@ -2643,7 +2643,7 @@ describe('DOMPluginEventSystem', () => {
expect(log[5]).toEqual(['bubble', buttonElement]);
});
// @gate experimental && enableEagerRootListeners
// @gate experimental
it('propagates known createEventHandle events through portals without inner listeners', () => {
const buttonRef = React.createRef();
const divRef = React.createRef();
+1 -22
View File
@@ -16,14 +16,10 @@ import {canUseDOM} from 'shared/ExecutionEnvironment';
import {SyntheticEvent} from '../../events/SyntheticEvent';
import isTextInputElement from '../isTextInputElement';
import shallowEqual from 'shared/shallowEqual';
import {enableEagerRootListeners} from 'shared/ReactFeatureFlags';
import {registerTwoPhaseEvent} from '../EventRegistry';
import getActiveElement from '../../client/getActiveElement';
import {
getNodeFromInstance,
getEventListenerSet,
} from '../../client/ReactDOMComponentTree';
import {getNodeFromInstance} from '../../client/ReactDOMComponentTree';
import {hasSelectionCapabilities} from '../../client/ReactInputSelection';
import {DOCUMENT_NODE} from '../../shared/HTMLNodeType';
import {accumulateTwoPhaseListeners} from '../DOMPluginEventSystem';
@@ -154,23 +150,6 @@ function extractEvents(
eventSystemFlags: EventSystemFlags,
targetContainer: EventTarget,
) {
if (!enableEagerRootListeners) {
const eventListenerSet = getEventListenerSet(targetContainer);
// Track whether all listeners exists for this plugin. If none exist, we do
// not extract events. See #3639.
if (
// If we are handling selectionchange, then we don't need to
// check for the other dependencies, as selectionchange is only
// event attached from the onChange plugin and we don't expose an
// onSelectionChange event from React.
domEventName !== 'selectionchange' &&
!eventListenerSet.has('onSelect') &&
!eventListenerSet.has('onSelectCapture')
) {
return;
}
}
const targetNode = targetInst ? getNodeFromInstance(targetInst) : window;
switch (domEventName) {
@@ -516,36 +516,16 @@ describe('SimpleEventPlugin', function() {
return nativeAddEventListener.apply(this, arguments);
};
ReactDOM.render(
<div
// Affected by the intervention:
// https://github.com/facebook/react/issues/19651
onTouchStart={() => {}}
onTouchMove={() => {}}
onWheel={() => {}}
// A few events that should be unaffected:
onClick={() => {}}
onScroll={() => {}}
onTouchEnd={() => {}}
onChange={() => {}}
onPointerDown={() => {}}
onPointerMove={() => {}}
/>,
container,
);
ReactDOM.render(<div />, container);
if (gate(flags => flags.enableEagerRootListeners)) {
expect(passiveEvents).toEqual([
'touchstart',
'touchstart',
'touchmove',
'touchmove',
'wheel',
'wheel',
]);
} else {
expect(passiveEvents).toEqual(['touchstart', 'touchmove', 'wheel']);
}
expect(passiveEvents).toEqual([
'touchstart',
'touchstart',
'touchmove',
'touchmove',
'wheel',
'wheel',
]);
});
});
});
-2
View File
@@ -133,6 +133,4 @@ export const decoupleUpdatePriorityFromScheduler = false;
export const enableDiscreteEventFlushingChange = false;
export const enableEagerRootListeners = true;
export const enableDoubleInvokingEffects = false;
@@ -49,7 +49,6 @@ export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true;
export const decoupleUpdatePriorityFromScheduler = false;
export const enableDiscreteEventFlushingChange = false;
export const enableEagerRootListeners = true;
export const enableDoubleInvokingEffects = false;
@@ -48,7 +48,6 @@ export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true;
export const decoupleUpdatePriorityFromScheduler = false;
export const enableDiscreteEventFlushingChange = false;
export const enableEagerRootListeners = true;
export const enableDoubleInvokingEffects = false;
@@ -48,7 +48,6 @@ export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true;
export const decoupleUpdatePriorityFromScheduler = false;
export const enableDiscreteEventFlushingChange = false;
export const enableEagerRootListeners = true;
export const enableDoubleInvokingEffects = false;
@@ -48,7 +48,6 @@ export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true;
export const decoupleUpdatePriorityFromScheduler = false;
export const enableDiscreteEventFlushingChange = false;
export const enableEagerRootListeners = true;
export const enableDoubleInvokingEffects = false;
@@ -48,7 +48,6 @@ export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true;
export const decoupleUpdatePriorityFromScheduler = false;
export const enableDiscreteEventFlushingChange = false;
export const enableEagerRootListeners = true;
export const enableDoubleInvokingEffects = false;
@@ -48,7 +48,6 @@ export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true;
export const decoupleUpdatePriorityFromScheduler = false;
export const enableDiscreteEventFlushingChange = false;
export const enableEagerRootListeners = true;
export const enableDoubleInvokingEffects = false;
@@ -48,7 +48,6 @@ export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = true;
export const decoupleUpdatePriorityFromScheduler = false;
export const enableDiscreteEventFlushingChange = true;
export const enableEagerRootListeners = true;
export const enableDoubleInvokingEffects = false;
@@ -19,7 +19,6 @@ export const enableFilterEmptyStringAttributesDOM = __VARIANT__;
export const enableLegacyFBSupport = __VARIANT__;
export const decoupleUpdatePriorityFromScheduler = __VARIANT__;
export const skipUnmountedBoundaries = __VARIANT__;
export const enableEagerRootListeners = !__VARIANT__;
// Enable this flag to help with concurrent mode debugging.
// It logs information to the console about React scheduling, rendering, and commit phases.
@@ -27,7 +27,6 @@ export const {
decoupleUpdatePriorityFromScheduler,
enableDebugTracing,
skipUnmountedBoundaries,
enableEagerRootListeners,
enableDoubleInvokingEffects,
} = dynamicFeatureFlags;