From 23e5edd05c1f89dc7a23452afabd02003c225858 Mon Sep 17 00:00:00 2001 From: Ricky Date: Sat, 17 Jan 2026 12:46:05 -0500 Subject: [PATCH 1/2] [flags] clean up enableUseEffectEventHook (#35541) This is landed everywhere --- .../src/__tests__/ReactDOMFizzServer-test.js | 3 - .../src/ReactFiberCommitWork.js | 34 ++- .../react-reconciler/src/ReactFiberFlags.js | 13 +- .../react-reconciler/src/ReactFiberHooks.js | 142 +++++------ .../src/ReactInternalTypes.js | 3 +- .../src/__tests__/useEffectEvent-test.js | 220 +++++++++++++++++- packages/react-server/src/ReactFizzHooks.js | 7 +- packages/react-server/src/ReactFlightHooks.js | 5 +- packages/shared/ReactFeatureFlags.js | 6 +- .../ReactFeatureFlags.native-fb-dynamic.js | 1 + .../forks/ReactFeatureFlags.native-fb.js | 2 +- .../forks/ReactFeatureFlags.native-oss.js | 2 +- .../forks/ReactFeatureFlags.test-renderer.js | 2 +- ...actFeatureFlags.test-renderer.native-fb.js | 2 +- .../ReactFeatureFlags.test-renderer.www.js | 2 +- .../forks/ReactFeatureFlags.www-dynamic.js | 2 + .../shared/forks/ReactFeatureFlags.www.js | 2 +- 17 files changed, 309 insertions(+), 139 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js index 7d4220460d9..bd0c6107f37 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js @@ -6509,7 +6509,6 @@ describe('ReactDOMFizzServer', () => { }); describe('useEffectEvent', () => { - // @gate enableUseEffectEventHook it('can server render a component with useEffectEvent', async () => { const ref = React.createRef(); function App() { @@ -6540,7 +6539,6 @@ describe('ReactDOMFizzServer', () => { expect(getVisibleChildren(container)).toEqual(); }); - // @gate enableUseEffectEventHook it('throws if useEffectEvent is called during a server render', async () => { const logs = []; function App() { @@ -6572,7 +6570,6 @@ describe('ReactDOMFizzServer', () => { expect(reportedServerErrors).toEqual([caughtError]); }); - // @gate enableUseEffectEventHook it('does not guarantee useEffectEvent return values during server rendering are distinct', async () => { function App() { const onClick1 = React.useEffectEvent(() => {}); diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index ecacb0c1585..946e758c1dc 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -47,6 +47,7 @@ import type {ViewTransitionState} from './ReactFiberViewTransitionComponent'; import { alwaysThrottleRetries, enableCreateEventHandleAPI, + enableEffectEventMutationPhase, enableHiddenSubtreeInsertionEffectCleanup, enableProfilerTimer, enableProfilerCommitHooks, @@ -54,7 +55,6 @@ import { enableScopeAPI, enableUpdaterTracking, enableTransitionTracing, - enableUseEffectEventHook, enableLegacyHidden, disableLegacyMode, enableComponentPerformanceTrack, @@ -500,17 +500,14 @@ function commitBeforeMutationEffectsOnFiber( case FunctionComponent: case ForwardRef: case SimpleMemoComponent: { - if (enableUseEffectEventHook) { - if ((flags & Update) !== NoFlags) { - const updateQueue: FunctionComponentUpdateQueue | null = - (finishedWork.updateQueue: any); - const eventPayloads = - updateQueue !== null ? updateQueue.events : null; - if (eventPayloads !== null) { - for (let ii = 0; ii < eventPayloads.length; ii++) { - const {ref, nextImpl} = eventPayloads[ii]; - ref.impl = nextImpl; - } + if (!enableEffectEventMutationPhase && (flags & Update) !== NoFlags) { + const updateQueue: FunctionComponentUpdateQueue | null = + (finishedWork.updateQueue: any); + const eventPayloads = updateQueue !== null ? updateQueue.events : null; + if (eventPayloads !== null) { + for (let ii = 0; ii < eventPayloads.length; ii++) { + const {ref, nextImpl} = eventPayloads[ii]; + ref.impl = nextImpl; } } } @@ -2050,6 +2047,19 @@ function commitMutationEffectsOnFiber( commitReconciliationEffects(finishedWork, lanes); if (flags & Update) { + // Mutate event effect callbacks before insertion effects. + if (enableEffectEventMutationPhase) { + const updateQueue: FunctionComponentUpdateQueue | null = + (finishedWork.updateQueue: any); + const eventPayloads = + updateQueue !== null ? updateQueue.events : null; + if (eventPayloads !== null) { + for (let ii = 0; ii < eventPayloads.length; ii++) { + const {ref, nextImpl} = eventPayloads[ii]; + ref.impl = nextImpl; + } + } + } commitHookEffectListUnmount( HookInsertion | HookHasEffect, finishedWork, diff --git a/packages/react-reconciler/src/ReactFiberFlags.js b/packages/react-reconciler/src/ReactFiberFlags.js index 7fa1dcb8173..9f85897fb05 100644 --- a/packages/react-reconciler/src/ReactFiberFlags.js +++ b/packages/react-reconciler/src/ReactFiberFlags.js @@ -9,7 +9,7 @@ import { enableCreateEventHandleAPI, - enableUseEffectEventHook, + enableEffectEventMutationPhase, } from 'shared/ReactFeatureFlags'; export type Flags = number; @@ -102,12 +102,11 @@ export const BeforeMutationMask: number = // TODO: Only need to visit Deletions during BeforeMutation phase if an // element is focused. Update | ChildDeletion | Visibility - : enableUseEffectEventHook - ? // TODO: The useEffectEvent hook uses the snapshot phase for clean up but it - // really should use the mutation phase for this or at least schedule an - // explicit Snapshot phase flag for this. - Update - : 0); + : // useEffectEvent uses the snapshot phase, + // but we're moving it to the mutation phase. + enableEffectEventMutationPhase + ? 0 + : Update); // For View Transition support we use the snapshot phase to scan the tree for potentially // affected ViewTransition components. diff --git a/packages/react-reconciler/src/ReactFiberHooks.js b/packages/react-reconciler/src/ReactFiberHooks.js index 422667c6a12..0450495ff0d 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.js +++ b/packages/react-reconciler/src/ReactFiberHooks.js @@ -38,7 +38,6 @@ import ReactSharedInternals from 'shared/ReactSharedInternals'; import { enableSchedulingProfiler, enableTransitionTracing, - enableUseEffectEventHook, enableLegacyCache, disableLegacyMode, enableNoCloningMemoCache, @@ -3893,10 +3892,8 @@ export const ContextOnlyDispatcher: Dispatcher = { useOptimistic: throwInvalidHookError, useMemoCache: throwInvalidHookError, useCacheRefresh: throwInvalidHookError, + useEffectEvent: throwInvalidHookError, }; -if (enableUseEffectEventHook) { - (ContextOnlyDispatcher: Dispatcher).useEffectEvent = throwInvalidHookError; -} const HooksDispatcherOnMount: Dispatcher = { readContext, @@ -3923,10 +3920,8 @@ const HooksDispatcherOnMount: Dispatcher = { useOptimistic: mountOptimistic, useMemoCache, useCacheRefresh: mountRefresh, + useEffectEvent: mountEvent, }; -if (enableUseEffectEventHook) { - (HooksDispatcherOnMount: Dispatcher).useEffectEvent = mountEvent; -} const HooksDispatcherOnUpdate: Dispatcher = { readContext, @@ -3953,10 +3948,8 @@ const HooksDispatcherOnUpdate: Dispatcher = { useOptimistic: updateOptimistic, useMemoCache, useCacheRefresh: updateRefresh, + useEffectEvent: updateEvent, }; -if (enableUseEffectEventHook) { - (HooksDispatcherOnUpdate: Dispatcher).useEffectEvent = updateEvent; -} const HooksDispatcherOnRerender: Dispatcher = { readContext, @@ -3983,10 +3976,8 @@ const HooksDispatcherOnRerender: Dispatcher = { useOptimistic: rerenderOptimistic, useMemoCache, useCacheRefresh: updateRefresh, + useEffectEvent: updateEvent, }; -if (enableUseEffectEventHook) { - (HooksDispatcherOnRerender: Dispatcher).useEffectEvent = updateEvent; -} let HooksDispatcherOnMountInDEV: Dispatcher | null = null; let HooksDispatcherOnMountWithHookTypesInDEV: Dispatcher | null = null; @@ -4176,17 +4167,14 @@ if (__DEV__) { mountHookTypesDev(); return mountRefresh(); }, + useEffectEvent) => Return>( + callback: F, + ): F { + currentHookNameInDev = 'useEffectEvent'; + mountHookTypesDev(); + return mountEvent(callback); + }, }; - if (enableUseEffectEventHook) { - (HooksDispatcherOnMountInDEV: Dispatcher).useEffectEvent = - function useEffectEvent) => Return>( - callback: F, - ): F { - currentHookNameInDev = 'useEffectEvent'; - mountHookTypesDev(); - return mountEvent(callback); - }; - } HooksDispatcherOnMountWithHookTypesInDEV = { readContext(context: ReactContext): T { @@ -4343,17 +4331,14 @@ if (__DEV__) { updateHookTypesDev(); return mountRefresh(); }, + useEffectEvent) => Return>( + callback: F, + ): F { + currentHookNameInDev = 'useEffectEvent'; + updateHookTypesDev(); + return mountEvent(callback); + }, }; - if (enableUseEffectEventHook) { - (HooksDispatcherOnMountWithHookTypesInDEV: Dispatcher).useEffectEvent = - function useEffectEvent) => Return>( - callback: F, - ): F { - currentHookNameInDev = 'useEffectEvent'; - updateHookTypesDev(); - return mountEvent(callback); - }; - } HooksDispatcherOnUpdateInDEV = { readContext(context: ReactContext): T { @@ -4510,17 +4495,14 @@ if (__DEV__) { updateHookTypesDev(); return updateRefresh(); }, + useEffectEvent) => Return>( + callback: F, + ): F { + currentHookNameInDev = 'useEffectEvent'; + updateHookTypesDev(); + return updateEvent(callback); + }, }; - if (enableUseEffectEventHook) { - (HooksDispatcherOnUpdateInDEV: Dispatcher).useEffectEvent = - function useEffectEvent) => Return>( - callback: F, - ): F { - currentHookNameInDev = 'useEffectEvent'; - updateHookTypesDev(); - return updateEvent(callback); - }; - } HooksDispatcherOnRerenderInDEV = { readContext(context: ReactContext): T { @@ -4677,17 +4659,14 @@ if (__DEV__) { updateHookTypesDev(); return updateRefresh(); }, + useEffectEvent) => Return>( + callback: F, + ): F { + currentHookNameInDev = 'useEffectEvent'; + updateHookTypesDev(); + return updateEvent(callback); + }, }; - if (enableUseEffectEventHook) { - (HooksDispatcherOnRerenderInDEV: Dispatcher).useEffectEvent = - function useEffectEvent) => Return>( - callback: F, - ): F { - currentHookNameInDev = 'useEffectEvent'; - updateHookTypesDev(); - return updateEvent(callback); - }; - } InvalidNestedHooksDispatcherOnMountInDEV = { readContext(context: ReactContext): T { @@ -4868,18 +4847,15 @@ if (__DEV__) { mountHookTypesDev(); return mountRefresh(); }, + useEffectEvent) => Return>( + callback: F, + ): F { + currentHookNameInDev = 'useEffectEvent'; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountEvent(callback); + }, }; - if (enableUseEffectEventHook) { - (InvalidNestedHooksDispatcherOnMountInDEV: Dispatcher).useEffectEvent = - function useEffectEvent) => Return>( - callback: F, - ): F { - currentHookNameInDev = 'useEffectEvent'; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountEvent(callback); - }; - } InvalidNestedHooksDispatcherOnUpdateInDEV = { readContext(context: ReactContext): T { @@ -5060,18 +5036,15 @@ if (__DEV__) { updateHookTypesDev(); return updateRefresh(); }, + useEffectEvent) => Return>( + callback: F, + ): F { + currentHookNameInDev = 'useEffectEvent'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateEvent(callback); + }, }; - if (enableUseEffectEventHook) { - (InvalidNestedHooksDispatcherOnUpdateInDEV: Dispatcher).useEffectEvent = - function useEffectEvent) => Return>( - callback: F, - ): F { - currentHookNameInDev = 'useEffectEvent'; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateEvent(callback); - }; - } InvalidNestedHooksDispatcherOnRerenderInDEV = { readContext(context: ReactContext): T { @@ -5252,16 +5225,13 @@ if (__DEV__) { updateHookTypesDev(); return updateRefresh(); }, + useEffectEvent) => Return>( + callback: F, + ): F { + currentHookNameInDev = 'useEffectEvent'; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateEvent(callback); + }, }; - if (enableUseEffectEventHook) { - (InvalidNestedHooksDispatcherOnRerenderInDEV: Dispatcher).useEffectEvent = - function useEffectEvent) => Return>( - callback: F, - ): F { - currentHookNameInDev = 'useEffectEvent'; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateEvent(callback); - }; - } } diff --git a/packages/react-reconciler/src/ReactInternalTypes.js b/packages/react-reconciler/src/ReactInternalTypes.js index ce22050123c..d12c1e38694 100644 --- a/packages/react-reconciler/src/ReactInternalTypes.js +++ b/packages/react-reconciler/src/ReactInternalTypes.js @@ -409,8 +409,7 @@ export type Dispatcher = { create: () => (() => void) | void, deps: Array | void | null, ): void, - // TODO: Non-nullable once `enableUseEffectEventHook` is on everywhere. - useEffectEvent?: ) => mixed>(callback: F) => F, + useEffectEvent: ) => mixed>(callback: F) => F, useInsertionEffect( create: () => (() => void) | void, deps: Array | void | null, diff --git a/packages/react-reconciler/src/__tests__/useEffectEvent-test.js b/packages/react-reconciler/src/__tests__/useEffectEvent-test.js index f263c9af269..0d903d59e4a 100644 --- a/packages/react-reconciler/src/__tests__/useEffectEvent-test.js +++ b/packages/react-reconciler/src/__tests__/useEffectEvent-test.js @@ -53,7 +53,6 @@ describe('useEffectEvent', () => { return ; } - // @gate enableUseEffectEventHook it('memoizes basic case correctly', async () => { class IncrementButton extends React.PureComponent { increment = () => { @@ -129,7 +128,6 @@ describe('useEffectEvent', () => { ); }); - // @gate enableUseEffectEventHook it('can be defined more than once', async () => { class IncrementButton extends React.PureComponent { increment = () => { @@ -191,7 +189,6 @@ describe('useEffectEvent', () => { ); }); - // @gate enableUseEffectEventHook it('does not preserve `this` in event functions', async () => { class GreetButton extends React.PureComponent { greet = () => { @@ -241,7 +238,6 @@ describe('useEffectEvent', () => { ); }); - // @gate enableUseEffectEventHook it('throws when called in render', async () => { class IncrementButton extends React.PureComponent { increment = () => { @@ -275,7 +271,6 @@ describe('useEffectEvent', () => { assertLog([]); }); - // @gate enableUseEffectEventHook it("useLayoutEffect shouldn't re-fire when event handlers change", async () => { class IncrementButton extends React.PureComponent { increment = () => { @@ -375,7 +370,6 @@ describe('useEffectEvent', () => { ); }); - // @gate enableUseEffectEventHook it("useEffect shouldn't re-fire when event handlers change", async () => { class IncrementButton extends React.PureComponent { increment = () => { @@ -474,7 +468,6 @@ describe('useEffectEvent', () => { ); }); - // @gate enableUseEffectEventHook it('is stable in a custom hook', async () => { class IncrementButton extends React.PureComponent { increment = () => { @@ -579,7 +572,6 @@ describe('useEffectEvent', () => { ); }); - // @gate enableUseEffectEventHook it('is mutated before all other effects', async () => { function Counter({value}) { useInsertionEffect(() => { @@ -603,7 +595,214 @@ describe('useEffectEvent', () => { assertLog(['Effect value: 2', 'Event value: 2']); }); - // @gate enableUseEffectEventHook + it('updates parent and child event effects before their respective effect lifecycles', async () => { + function Parent({value}) { + const parentEvent = useEffectEvent(() => { + Scheduler.log('Parent event: ' + value); + }); + + useInsertionEffect(() => { + Scheduler.log('Parent insertion'); + parentEvent(); + }, [value]); + + return ; + } + + function Child({value}) { + const childEvent = useEffectEvent(() => { + Scheduler.log('Child event: ' + value); + }); + + useInsertionEffect(() => { + Scheduler.log('Child insertion'); + childEvent(); + }, [value]); + + return null; + } + + ReactNoop.render(); + await waitForAll([ + 'Child insertion', + 'Child event: 1', + 'Parent insertion', + 'Parent event: 1', + ]); + + await act(() => ReactNoop.render()); + // Each component's event is updated before its own insertion effect runs + assertLog([ + 'Child insertion', + 'Child event: 2', + 'Parent insertion', + 'Parent event: 2', + ]); + }); + + it('fires all insertion effects (interleaved) with useEffectEvent before firing any layout effects', async () => { + // This test mirrors the 'fires all insertion effects (interleaved) before firing any layout effects' + // test in ReactHooksWithNoopRenderer-test.js, but adds useEffectEvent to verify that + // event payloads are updated before each component's insertion effects run. + // It also includes passive effects to verify the full effect lifecycle. + let committedA = '(empty)'; + let committedB = '(empty)'; + + function CounterA(props) { + const onEvent = useEffectEvent(() => { + return `Event A [A: ${committedA}, B: ${committedB}]`; + }); + + useInsertionEffect(() => { + // Call the event function to verify it sees the latest value + Scheduler.log( + `Create Insertion A [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, + ); + committedA = String(props.count); + return () => { + Scheduler.log( + `Destroy Insertion A [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, + ); + }; + }); + + useLayoutEffect(() => { + Scheduler.log( + `Create Layout A [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, + ); + return () => { + Scheduler.log( + `Destroy Layout A [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, + ); + }; + }); + + useEffect(() => { + Scheduler.log( + `Create Passive A [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, + ); + return () => { + Scheduler.log( + `Destroy Passive A [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, + ); + }; + }); + + return null; + } + + function CounterB(props) { + const onEvent = useEffectEvent(() => { + return `Event B [A: ${committedA}, B: ${committedB}]`; + }); + + useInsertionEffect(() => { + // Call the event function to verify it sees the latest value + Scheduler.log( + `Create Insertion B [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, + ); + committedB = String(props.count); + return () => { + Scheduler.log( + `Destroy Insertion B [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, + ); + }; + }); + + useLayoutEffect(() => { + Scheduler.log( + `Create Layout B [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, + ); + return () => { + Scheduler.log( + `Destroy Layout B [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, + ); + }; + }); + + useEffect(() => { + Scheduler.log( + `Create Passive B [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, + ); + return () => { + Scheduler.log( + `Destroy Passive B [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, + ); + }; + }); + + return null; + } + + await act(async () => { + ReactNoop.render( + + + + , + ); + // All insertion effects fire before all layout effects, then passive effects + // Event functions should see the state AT THE TIME they're called + await waitForAll([ + // Insertion effects (mutation phase) + 'Create Insertion A [A: (empty), B: (empty)], event: Event A [A: (empty), B: (empty)]', + 'Create Insertion B [A: 0, B: (empty)], event: Event B [A: 0, B: (empty)]', + // Layout effects + 'Create Layout A [A: 0, B: 0], event: Event A [A: 0, B: 0]', + 'Create Layout B [A: 0, B: 0], event: Event B [A: 0, B: 0]', + // Passive effects + 'Create Passive A [A: 0, B: 0], event: Event A [A: 0, B: 0]', + 'Create Passive B [A: 0, B: 0], event: Event B [A: 0, B: 0]', + ]); + expect([committedA, committedB]).toEqual(['0', '0']); + }); + + await act(async () => { + ReactNoop.render( + + + + , + ); + await waitForAll([ + // Component A: insertion destroy, then create + 'Destroy Insertion A [A: 0, B: 0], event: Event A [A: 0, B: 0]', + 'Create Insertion A [A: 0, B: 0], event: Event A [A: 0, B: 0]', + // Component A: layout destroy (after insertion updated committedA) + 'Destroy Layout A [A: 1, B: 0], event: Event A [A: 1, B: 0]', + // Component B: insertion destroy, then create + 'Destroy Insertion B [A: 1, B: 0], event: Event B [A: 1, B: 0]', + 'Create Insertion B [A: 1, B: 0], event: Event B [A: 1, B: 0]', + // Component B: layout destroy (after insertion updated committedB) + 'Destroy Layout B [A: 1, B: 1], event: Event B [A: 1, B: 1]', + // Layout creates + 'Create Layout A [A: 1, B: 1], event: Event A [A: 1, B: 1]', + 'Create Layout B [A: 1, B: 1], event: Event B [A: 1, B: 1]', + // Passive destroys then creates + 'Destroy Passive A [A: 1, B: 1], event: Event A [A: 1, B: 1]', + 'Destroy Passive B [A: 1, B: 1], event: Event B [A: 1, B: 1]', + 'Create Passive A [A: 1, B: 1], event: Event A [A: 1, B: 1]', + 'Create Passive B [A: 1, B: 1], event: Event B [A: 1, B: 1]', + ]); + expect([committedA, committedB]).toEqual(['1', '1']); + }); + + // Unmount everything + await act(async () => { + ReactNoop.render(null); + await waitForAll([ + // Insertion and layout destroys (mutation/layout phase) + 'Destroy Insertion A [A: 1, B: 1], event: Event A [A: 1, B: 1]', + 'Destroy Layout A [A: 1, B: 1], event: Event A [A: 1, B: 1]', + 'Destroy Insertion B [A: 1, B: 1], event: Event B [A: 1, B: 1]', + 'Destroy Layout B [A: 1, B: 1], event: Event B [A: 1, B: 1]', + // Passive destroys + 'Destroy Passive A [A: 1, B: 1], event: Event A [A: 1, B: 1]', + 'Destroy Passive B [A: 1, B: 1], event: Event B [A: 1, B: 1]', + ]); + }); + }); + it("doesn't provide a stable identity", async () => { function Counter({shouldRender, value}) { const onClick = useEffectEvent(() => { @@ -642,7 +841,6 @@ describe('useEffectEvent', () => { ]); }); - // @gate enableUseEffectEventHook it('event handlers always see the latest committed value', async () => { let committedEventHandler = null; @@ -692,7 +890,6 @@ describe('useEffectEvent', () => { expect(committedEventHandler()).toBe('Value seen by useEffectEvent: 2'); }); - // @gate enableUseEffectEventHook it('integration: implements docs chat room example', async () => { function createConnection() { let connectedCallback; @@ -781,7 +978,6 @@ describe('useEffectEvent', () => { ); }); - // @gate enableUseEffectEventHook it('integration: implements the docs logVisit example', async () => { class AddToCartButton extends React.PureComponent { addToCart = () => { diff --git a/packages/react-server/src/ReactFizzHooks.js b/packages/react-server/src/ReactFizzHooks.js index 119c2a0778f..24e676fc710 100644 --- a/packages/react-server/src/ReactFizzHooks.js +++ b/packages/react-server/src/ReactFizzHooks.js @@ -38,7 +38,6 @@ import { } from './ReactFizzConfig'; import {createFastHash} from './ReactServerStreamConfig'; -import {enableUseEffectEventHook} from 'shared/ReactFeatureFlags'; import is from 'shared/objectIs'; import { REACT_CONTEXT_TYPE, @@ -833,6 +832,7 @@ export const HooksDispatcher: Dispatcher = supportsClientAPIs useHostTransitionStatus, useMemoCache, useCacheRefresh, + useEffectEvent, } : { readContext, @@ -858,12 +858,9 @@ export const HooksDispatcher: Dispatcher = supportsClientAPIs useOptimistic, useMemoCache, useCacheRefresh, + useEffectEvent, }; -if (enableUseEffectEventHook) { - HooksDispatcher.useEffectEvent = useEffectEvent; -} - export let currentResumableState: null | ResumableState = (null: any); export function setCurrentResumableState( resumableState: null | ResumableState, diff --git a/packages/react-server/src/ReactFlightHooks.js b/packages/react-server/src/ReactFlightHooks.js index ed369be0e9b..d814de46298 100644 --- a/packages/react-server/src/ReactFlightHooks.js +++ b/packages/react-server/src/ReactFlightHooks.js @@ -17,7 +17,6 @@ import { } from 'shared/ReactSymbols'; import {createThenableState, trackUsedThenable} from './ReactFlightThenable'; import {isClientReference} from './ReactFlightServerConfig'; -import {enableUseEffectEventHook} from 'shared/ReactFeatureFlags'; let currentRequest = null; let thenableIndexCounter = 0; @@ -101,10 +100,8 @@ export const HooksDispatcher: Dispatcher = { useCacheRefresh(): (?() => T, ?T) => void { return unsupportedRefresh; }, + useEffectEvent: (unsupportedHook: any), }; -if (enableUseEffectEventHook) { - HooksDispatcher.useEffectEvent = (unsupportedHook: any); -} function unsupportedHook(): void { throw new Error('This Hook is not supported in Server Components.'); diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index ebb287568af..3e68d8c8991 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -118,8 +118,6 @@ export const enableCPUSuspense = __EXPERIMENTAL__; // Test this at Meta before enabling. export const enableNoCloningMemoCache: boolean = false; -export const enableUseEffectEventHook: boolean = true; - // Test in www before enabling in open source. // Enables DOM-server to stream its instruction set as data-attributes // (handled with an MutationObserver) instead of inline-scripts @@ -127,6 +125,10 @@ export const enableFizzExternalRuntime = __EXPERIMENTAL__; export const alwaysThrottleRetries: boolean = true; +// Gate whether useEffectEvent uses the mutation phase (true) or before-mutation +// phase (false) for updating event function references. +export const enableEffectEventMutationPhase: boolean = false; + export const passChildrenWhenCloningPersistedNodes: boolean = false; export const enableEagerAlternateStateNodeCleanup: boolean = true; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js index f139a3fcf28..389d46be497 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js @@ -27,3 +27,4 @@ export const enableFragmentRefs = __VARIANT__; export const enableFragmentRefsScrollIntoView = __VARIANT__; export const enableFragmentRefsInstanceHandles = __VARIANT__; export const enableComponentPerformanceTrack = __VARIANT__; +export const enableEffectEventMutationPhase = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index d9a91f8a808..cb0b0b66f60 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -20,6 +20,7 @@ const dynamicFlags: DynamicExportsType = (dynamicFlagsUntyped: any); // the exports object every time a flag is read. export const { alwaysThrottleRetries, + enableEffectEventMutationPhase, enableHiddenSubtreeInsertionEffectCleanup, enableObjectFiber, enableEagerAlternateStateNodeCleanup, @@ -64,7 +65,6 @@ export const enableTaint: boolean = true; export const enableTransitionTracing: boolean = false; export const enableTrustedTypesIntegration: boolean = false; export const enableUpdaterTracking: boolean = __PROFILE__; -export const enableUseEffectEventHook: boolean = true; export const retryLaneExpirationMs = 5000; export const syncLaneExpirationMs = 250; export const transitionLaneExpirationMs = 5000; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index fa8f336c03f..f1e697b7b21 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -46,12 +46,12 @@ export const enableSchedulingProfiler: boolean = !enableComponentPerformanceTrack && __PROFILE__; export const enableScopeAPI: boolean = false; export const enableEagerAlternateStateNodeCleanup: boolean = true; +export const enableEffectEventMutationPhase: boolean = false; export const enableSuspenseAvoidThisFallback: boolean = false; export const enableSuspenseCallback: boolean = false; export const enableTaint: boolean = true; export const enableTransitionTracing: boolean = false; export const enableTrustedTypesIntegration: boolean = false; -export const enableUseEffectEventHook: boolean = true; export const passChildrenWhenCloningPersistedNodes: boolean = false; export const renameElementSymbol: boolean = true; export const retryLaneExpirationMs = 5000; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index acf3847bd06..8e65aea17b2 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -32,7 +32,6 @@ export const disableTextareaChildren: boolean = false; export const enableSuspenseAvoidThisFallback: boolean = false; export const enableCPUSuspense: boolean = false; export const enableNoCloningMemoCache: boolean = false; -export const enableUseEffectEventHook: boolean = true; export const enableLegacyFBSupport: boolean = false; export const enableMoveBefore: boolean = false; export const enableHiddenSubtreeInsertionEffectCleanup: boolean = false; @@ -59,6 +58,7 @@ export const enableInfiniteRenderLoopDetection: boolean = false; export const renameElementSymbol: boolean = true; export const enableEagerAlternateStateNodeCleanup: boolean = true; +export const enableEffectEventMutationPhase: boolean = false; export const enableYieldingBeforePassive: boolean = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index 5d3a5513018..120a20160f8 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -43,13 +43,13 @@ export const enableComponentPerformanceTrack = false; export const enablePerformanceIssueReporting = false; export const enableScopeAPI = false; export const enableEagerAlternateStateNodeCleanup = true; +export const enableEffectEventMutationPhase = false; export const enableSuspenseAvoidThisFallback = false; export const enableSuspenseCallback = false; export const enableTaint = true; export const enableTransitionTracing = false; export const enableTrustedTypesIntegration = false; export const enableUpdaterTracking = false; -export const enableUseEffectEventHook = true; export const passChildrenWhenCloningPersistedNodes = false; export const renameElementSymbol = false; export const retryLaneExpirationMs = 5000; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 553be202c45..dee7642449a 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -34,7 +34,6 @@ export const disableTextareaChildren: boolean = false; export const enableSuspenseAvoidThisFallback: boolean = true; export const enableCPUSuspense: boolean = false; export const enableNoCloningMemoCache: boolean = false; -export const enableUseEffectEventHook: boolean = true; export const enableLegacyFBSupport: boolean = false; export const enableMoveBefore: boolean = false; export const enableHiddenSubtreeInsertionEffectCleanup: boolean = true; @@ -65,6 +64,7 @@ export const renameElementSymbol: boolean = false; export const enableObjectFiber: boolean = false; export const enableEagerAlternateStateNodeCleanup: boolean = true; +export const enableEffectEventMutationPhase: boolean = false; export const enableHydrationLaneScheduling: boolean = true; diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js index 1d174609cb9..206e9ec3a36 100644 --- a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js @@ -40,6 +40,8 @@ export const enableAsyncDebugInfo: boolean = __VARIANT__; export const enableInternalInstanceMap: boolean = __VARIANT__; +export const enableEffectEventMutationPhase: boolean = __VARIANT__; + // TODO: These flags are hard-coded to the default values used in open source. // Update the tests so that they pass in either mode, then set these // to __VARIANT__. diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 87801a9658f..1db222df0bc 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -18,6 +18,7 @@ export const { alwaysThrottleRetries, disableLegacyContextForFunctionComponents, disableSchedulerTimeoutInWorkLoop, + enableEffectEventMutationPhase, enableHiddenSubtreeInsertionEffectCleanup, enableInfiniteRenderLoopDetection, enableNoCloningMemoCache, @@ -49,7 +50,6 @@ export const enableUpdaterTracking = __PROFILE__; export const enableSuspenseAvoidThisFallback: boolean = true; export const enableCPUSuspense: boolean = true; -export const enableUseEffectEventHook: boolean = true; export const enableMoveBefore: boolean = false; export const disableInputAttributeSyncing: boolean = false; export const enableLegacyFBSupport: boolean = true; From be3fb29904a23322bd3cef7752df517fabdc188a Mon Sep 17 00:00:00 2001 From: Ricky Date: Sat, 17 Jan 2026 13:21:46 -0500 Subject: [PATCH 2/2] [internal] revert change merged accidentally (#35546) I accidentally pushed this to new flag to https://github.com/facebook/react/pull/35541 and then merged it. Reverting it so I can submit a review. --- .../src/ReactFiberCommitWork.js | 16 +- .../react-reconciler/src/ReactFiberFlags.js | 14 +- .../src/__tests__/useEffectEvent-test.js | 208 ------------------ packages/shared/ReactFeatureFlags.js | 4 - .../ReactFeatureFlags.native-fb-dynamic.js | 1 - .../forks/ReactFeatureFlags.native-fb.js | 1 - .../forks/ReactFeatureFlags.native-oss.js | 1 - .../forks/ReactFeatureFlags.test-renderer.js | 1 - ...actFeatureFlags.test-renderer.native-fb.js | 1 - .../ReactFeatureFlags.test-renderer.www.js | 1 - .../forks/ReactFeatureFlags.www-dynamic.js | 2 - .../shared/forks/ReactFeatureFlags.www.js | 1 - 12 files changed, 6 insertions(+), 245 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index 946e758c1dc..43db744007d 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -47,7 +47,6 @@ import type {ViewTransitionState} from './ReactFiberViewTransitionComponent'; import { alwaysThrottleRetries, enableCreateEventHandleAPI, - enableEffectEventMutationPhase, enableHiddenSubtreeInsertionEffectCleanup, enableProfilerTimer, enableProfilerCommitHooks, @@ -500,7 +499,7 @@ function commitBeforeMutationEffectsOnFiber( case FunctionComponent: case ForwardRef: case SimpleMemoComponent: { - if (!enableEffectEventMutationPhase && (flags & Update) !== NoFlags) { + if ((flags & Update) !== NoFlags) { const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any); const eventPayloads = updateQueue !== null ? updateQueue.events : null; @@ -2047,19 +2046,6 @@ function commitMutationEffectsOnFiber( commitReconciliationEffects(finishedWork, lanes); if (flags & Update) { - // Mutate event effect callbacks before insertion effects. - if (enableEffectEventMutationPhase) { - const updateQueue: FunctionComponentUpdateQueue | null = - (finishedWork.updateQueue: any); - const eventPayloads = - updateQueue !== null ? updateQueue.events : null; - if (eventPayloads !== null) { - for (let ii = 0; ii < eventPayloads.length; ii++) { - const {ref, nextImpl} = eventPayloads[ii]; - ref.impl = nextImpl; - } - } - } commitHookEffectListUnmount( HookInsertion | HookHasEffect, finishedWork, diff --git a/packages/react-reconciler/src/ReactFiberFlags.js b/packages/react-reconciler/src/ReactFiberFlags.js index 9f85897fb05..2d8d3f7fd16 100644 --- a/packages/react-reconciler/src/ReactFiberFlags.js +++ b/packages/react-reconciler/src/ReactFiberFlags.js @@ -7,10 +7,7 @@ * @flow */ -import { - enableCreateEventHandleAPI, - enableEffectEventMutationPhase, -} from 'shared/ReactFeatureFlags'; +import {enableCreateEventHandleAPI} from 'shared/ReactFeatureFlags'; export type Flags = number; @@ -102,11 +99,10 @@ export const BeforeMutationMask: number = // TODO: Only need to visit Deletions during BeforeMutation phase if an // element is focused. Update | ChildDeletion | Visibility - : // useEffectEvent uses the snapshot phase, - // but we're moving it to the mutation phase. - enableEffectEventMutationPhase - ? 0 - : Update); + : // TODO: The useEffectEvent hook uses the snapshot phase for clean up but it + // really should use the mutation phase for this or at least schedule an + // explicit Snapshot phase flag for this. + Update); // For View Transition support we use the snapshot phase to scan the tree for potentially // affected ViewTransition components. diff --git a/packages/react-reconciler/src/__tests__/useEffectEvent-test.js b/packages/react-reconciler/src/__tests__/useEffectEvent-test.js index 0d903d59e4a..2b5af2206b9 100644 --- a/packages/react-reconciler/src/__tests__/useEffectEvent-test.js +++ b/packages/react-reconciler/src/__tests__/useEffectEvent-test.js @@ -595,214 +595,6 @@ describe('useEffectEvent', () => { assertLog(['Effect value: 2', 'Event value: 2']); }); - it('updates parent and child event effects before their respective effect lifecycles', async () => { - function Parent({value}) { - const parentEvent = useEffectEvent(() => { - Scheduler.log('Parent event: ' + value); - }); - - useInsertionEffect(() => { - Scheduler.log('Parent insertion'); - parentEvent(); - }, [value]); - - return ; - } - - function Child({value}) { - const childEvent = useEffectEvent(() => { - Scheduler.log('Child event: ' + value); - }); - - useInsertionEffect(() => { - Scheduler.log('Child insertion'); - childEvent(); - }, [value]); - - return null; - } - - ReactNoop.render(); - await waitForAll([ - 'Child insertion', - 'Child event: 1', - 'Parent insertion', - 'Parent event: 1', - ]); - - await act(() => ReactNoop.render()); - // Each component's event is updated before its own insertion effect runs - assertLog([ - 'Child insertion', - 'Child event: 2', - 'Parent insertion', - 'Parent event: 2', - ]); - }); - - it('fires all insertion effects (interleaved) with useEffectEvent before firing any layout effects', async () => { - // This test mirrors the 'fires all insertion effects (interleaved) before firing any layout effects' - // test in ReactHooksWithNoopRenderer-test.js, but adds useEffectEvent to verify that - // event payloads are updated before each component's insertion effects run. - // It also includes passive effects to verify the full effect lifecycle. - let committedA = '(empty)'; - let committedB = '(empty)'; - - function CounterA(props) { - const onEvent = useEffectEvent(() => { - return `Event A [A: ${committedA}, B: ${committedB}]`; - }); - - useInsertionEffect(() => { - // Call the event function to verify it sees the latest value - Scheduler.log( - `Create Insertion A [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, - ); - committedA = String(props.count); - return () => { - Scheduler.log( - `Destroy Insertion A [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, - ); - }; - }); - - useLayoutEffect(() => { - Scheduler.log( - `Create Layout A [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, - ); - return () => { - Scheduler.log( - `Destroy Layout A [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, - ); - }; - }); - - useEffect(() => { - Scheduler.log( - `Create Passive A [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, - ); - return () => { - Scheduler.log( - `Destroy Passive A [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, - ); - }; - }); - - return null; - } - - function CounterB(props) { - const onEvent = useEffectEvent(() => { - return `Event B [A: ${committedA}, B: ${committedB}]`; - }); - - useInsertionEffect(() => { - // Call the event function to verify it sees the latest value - Scheduler.log( - `Create Insertion B [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, - ); - committedB = String(props.count); - return () => { - Scheduler.log( - `Destroy Insertion B [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, - ); - }; - }); - - useLayoutEffect(() => { - Scheduler.log( - `Create Layout B [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, - ); - return () => { - Scheduler.log( - `Destroy Layout B [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, - ); - }; - }); - - useEffect(() => { - Scheduler.log( - `Create Passive B [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, - ); - return () => { - Scheduler.log( - `Destroy Passive B [A: ${committedA}, B: ${committedB}], event: ${onEvent()}`, - ); - }; - }); - - return null; - } - - await act(async () => { - ReactNoop.render( - - - - , - ); - // All insertion effects fire before all layout effects, then passive effects - // Event functions should see the state AT THE TIME they're called - await waitForAll([ - // Insertion effects (mutation phase) - 'Create Insertion A [A: (empty), B: (empty)], event: Event A [A: (empty), B: (empty)]', - 'Create Insertion B [A: 0, B: (empty)], event: Event B [A: 0, B: (empty)]', - // Layout effects - 'Create Layout A [A: 0, B: 0], event: Event A [A: 0, B: 0]', - 'Create Layout B [A: 0, B: 0], event: Event B [A: 0, B: 0]', - // Passive effects - 'Create Passive A [A: 0, B: 0], event: Event A [A: 0, B: 0]', - 'Create Passive B [A: 0, B: 0], event: Event B [A: 0, B: 0]', - ]); - expect([committedA, committedB]).toEqual(['0', '0']); - }); - - await act(async () => { - ReactNoop.render( - - - - , - ); - await waitForAll([ - // Component A: insertion destroy, then create - 'Destroy Insertion A [A: 0, B: 0], event: Event A [A: 0, B: 0]', - 'Create Insertion A [A: 0, B: 0], event: Event A [A: 0, B: 0]', - // Component A: layout destroy (after insertion updated committedA) - 'Destroy Layout A [A: 1, B: 0], event: Event A [A: 1, B: 0]', - // Component B: insertion destroy, then create - 'Destroy Insertion B [A: 1, B: 0], event: Event B [A: 1, B: 0]', - 'Create Insertion B [A: 1, B: 0], event: Event B [A: 1, B: 0]', - // Component B: layout destroy (after insertion updated committedB) - 'Destroy Layout B [A: 1, B: 1], event: Event B [A: 1, B: 1]', - // Layout creates - 'Create Layout A [A: 1, B: 1], event: Event A [A: 1, B: 1]', - 'Create Layout B [A: 1, B: 1], event: Event B [A: 1, B: 1]', - // Passive destroys then creates - 'Destroy Passive A [A: 1, B: 1], event: Event A [A: 1, B: 1]', - 'Destroy Passive B [A: 1, B: 1], event: Event B [A: 1, B: 1]', - 'Create Passive A [A: 1, B: 1], event: Event A [A: 1, B: 1]', - 'Create Passive B [A: 1, B: 1], event: Event B [A: 1, B: 1]', - ]); - expect([committedA, committedB]).toEqual(['1', '1']); - }); - - // Unmount everything - await act(async () => { - ReactNoop.render(null); - await waitForAll([ - // Insertion and layout destroys (mutation/layout phase) - 'Destroy Insertion A [A: 1, B: 1], event: Event A [A: 1, B: 1]', - 'Destroy Layout A [A: 1, B: 1], event: Event A [A: 1, B: 1]', - 'Destroy Insertion B [A: 1, B: 1], event: Event B [A: 1, B: 1]', - 'Destroy Layout B [A: 1, B: 1], event: Event B [A: 1, B: 1]', - // Passive destroys - 'Destroy Passive A [A: 1, B: 1], event: Event A [A: 1, B: 1]', - 'Destroy Passive B [A: 1, B: 1], event: Event B [A: 1, B: 1]', - ]); - }); - }); - it("doesn't provide a stable identity", async () => { function Counter({shouldRender, value}) { const onClick = useEffectEvent(() => { diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 3e68d8c8991..587e4e6a1da 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -125,10 +125,6 @@ export const enableFizzExternalRuntime = __EXPERIMENTAL__; export const alwaysThrottleRetries: boolean = true; -// Gate whether useEffectEvent uses the mutation phase (true) or before-mutation -// phase (false) for updating event function references. -export const enableEffectEventMutationPhase: boolean = false; - export const passChildrenWhenCloningPersistedNodes: boolean = false; export const enableEagerAlternateStateNodeCleanup: boolean = true; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js index 389d46be497..f139a3fcf28 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js @@ -27,4 +27,3 @@ export const enableFragmentRefs = __VARIANT__; export const enableFragmentRefsScrollIntoView = __VARIANT__; export const enableFragmentRefsInstanceHandles = __VARIANT__; export const enableComponentPerformanceTrack = __VARIANT__; -export const enableEffectEventMutationPhase = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index cb0b0b66f60..e2674b70fee 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -20,7 +20,6 @@ const dynamicFlags: DynamicExportsType = (dynamicFlagsUntyped: any); // the exports object every time a flag is read. export const { alwaysThrottleRetries, - enableEffectEventMutationPhase, enableHiddenSubtreeInsertionEffectCleanup, enableObjectFiber, enableEagerAlternateStateNodeCleanup, diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index f1e697b7b21..672c3755108 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -46,7 +46,6 @@ export const enableSchedulingProfiler: boolean = !enableComponentPerformanceTrack && __PROFILE__; export const enableScopeAPI: boolean = false; export const enableEagerAlternateStateNodeCleanup: boolean = true; -export const enableEffectEventMutationPhase: boolean = false; export const enableSuspenseAvoidThisFallback: boolean = false; export const enableSuspenseCallback: boolean = false; export const enableTaint: boolean = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 8e65aea17b2..67c08d94367 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -58,7 +58,6 @@ export const enableInfiniteRenderLoopDetection: boolean = false; export const renameElementSymbol: boolean = true; export const enableEagerAlternateStateNodeCleanup: boolean = true; -export const enableEffectEventMutationPhase: boolean = false; export const enableYieldingBeforePassive: boolean = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index 120a20160f8..a0ee01baa7d 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -43,7 +43,6 @@ export const enableComponentPerformanceTrack = false; export const enablePerformanceIssueReporting = false; export const enableScopeAPI = false; export const enableEagerAlternateStateNodeCleanup = true; -export const enableEffectEventMutationPhase = false; export const enableSuspenseAvoidThisFallback = false; export const enableSuspenseCallback = false; export const enableTaint = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index dee7642449a..058fd752d6e 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -64,7 +64,6 @@ export const renameElementSymbol: boolean = false; export const enableObjectFiber: boolean = false; export const enableEagerAlternateStateNodeCleanup: boolean = true; -export const enableEffectEventMutationPhase: boolean = false; export const enableHydrationLaneScheduling: boolean = true; diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js index 206e9ec3a36..1d174609cb9 100644 --- a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js @@ -40,8 +40,6 @@ export const enableAsyncDebugInfo: boolean = __VARIANT__; export const enableInternalInstanceMap: boolean = __VARIANT__; -export const enableEffectEventMutationPhase: boolean = __VARIANT__; - // TODO: These flags are hard-coded to the default values used in open source. // Update the tests so that they pass in either mode, then set these // to __VARIANT__. diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 1db222df0bc..0752f266afc 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -18,7 +18,6 @@ export const { alwaysThrottleRetries, disableLegacyContextForFunctionComponents, disableSchedulerTimeoutInWorkLoop, - enableEffectEventMutationPhase, enableHiddenSubtreeInsertionEffectCleanup, enableInfiniteRenderLoopDetection, enableNoCloningMemoCache,