[crud] Revert CRUD overload (#32741)

Cleans up this experiment. After some internal experimentation we are
deprioritizing this project for now and may revisit it at a later point.
This commit is contained in:
lauren
2025-03-26 12:04:57 -04:00
committed by GitHub
parent f99c9feaf7
commit 313332d111
17 changed files with 66 additions and 1458 deletions
+2 -5
View File
@@ -374,11 +374,8 @@ function useInsertionEffect(
}
function useEffect(
create: (() => (() => void) | void) | (() => {...} | void | null),
createDeps: Array<mixed> | void | null,
update?: ((resource: {...} | void | null) => void) | void,
updateDeps?: Array<mixed> | void | null,
destroy?: ((resource: {...} | void | null) => void) | void,
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
nextHook();
hookLog.push({
@@ -653,52 +653,6 @@ describe('ReactDOMServerHooks', () => {
});
});
describe('useEffect with CRUD overload', () => {
gate(flags => {
if (flags.enableUseEffectCRUDOverload) {
const yields = [];
itRenders(
'should ignore resource effects on the server',
async render => {
function Counter(props) {
useEffect(
() => {
yieldValue('created on client');
return {resource_counter: props.count};
},
[props.count],
resource => {
resource.resource_counter = props.count;
yieldValue('updated on client');
},
[props.count],
() => {
yieldValue('cleanup on client');
},
);
return <Text text={'Count: ' + props.count} />;
}
const domNode = await render(<Counter count={0} />);
yields.push(clearLog());
expect(domNode.tagName).toEqual('SPAN');
expect(domNode.textContent).toEqual('Count: 0');
},
);
it('verifies yields in order', () => {
expect(yields).toEqual([
['Count: 0'], // server render
['Count: 0'], // server stream
['Count: 0', 'created on client'], // clean render
['Count: 0', 'created on client'], // hydrated render
// nothing yielded for bad markup
]);
});
}
});
});
describe('useContext', () => {
itThrowsWhenRendering(
'if used inside a class component',
+5 -50
View File
@@ -14,11 +14,6 @@ import type {CapturedValue} from './ReactCapturedValue';
import {isRendering, setIsRendering} from './ReactCurrentFiber';
import {captureCommitPhaseError} from './ReactFiberWorkLoop';
import {
ResourceEffectIdentityKind,
ResourceEffectUpdateKind,
} from './ReactFiberHooks';
import {enableUseEffectCRUDOverload} from 'shared/ReactFeatureFlags';
// These indirections exists so we can exclude its stack frame in DEV (and anything below it).
// TODO: Consider marking the whole bundle instead of these boundaries.
@@ -184,51 +179,11 @@ const callCreate = {
'react-stack-bottom-frame': function (
effect: Effect,
): (() => void) | {...} | void | null {
if (!enableUseEffectCRUDOverload) {
if (effect.resourceKind != null) {
if (__DEV__) {
console.error(
'Expected only SimpleEffects when enableUseEffectCRUDOverload is disabled, ' +
'got %s',
effect.resourceKind,
);
}
}
const create = effect.create;
const inst = effect.inst;
// $FlowFixMe[not-a-function] (@poteto)
const destroy = create();
// $FlowFixMe[incompatible-type] (@poteto)
inst.destroy = destroy;
return destroy;
} else {
if (effect.resourceKind == null) {
const create = effect.create;
const inst = effect.inst;
const destroy = create();
inst.destroy = destroy;
return destroy;
}
switch (effect.resourceKind) {
case ResourceEffectIdentityKind: {
return effect.create();
}
case ResourceEffectUpdateKind: {
if (typeof effect.update === 'function') {
effect.update(effect.inst.resource);
}
break;
}
default: {
if (__DEV__) {
console.error(
'Unhandled Effect kind %s. This is a bug in React.',
effect.kind,
);
}
}
}
}
const create = effect.create;
const inst = effect.inst;
const destroy = create();
inst.destroy = destroy;
return destroy;
},
};
+7 -125
View File
@@ -23,7 +23,6 @@ import {
enableProfilerCommitHooks,
enableProfilerNestedUpdatePhase,
enableSchedulingProfiler,
enableUseEffectCRUDOverload,
enableViewTransition,
enableFragmentRefs,
} from 'shared/ReactFeatureFlags';
@@ -62,7 +61,6 @@ import {
Layout as HookLayout,
Insertion as HookInsertion,
Passive as HookPassive,
HasEffect as HookHasEffect,
} from './ReactHookEffectTags';
import {didWarnAboutReassigningProps} from './ReactFiberBeginWork';
import {
@@ -84,10 +82,6 @@ import {
} from './ReactFiberCallUserSpace';
import {runWithFiberInDEV} from './ReactCurrentFiber';
import {
ResourceEffectIdentityKind,
ResourceEffectUpdateKind,
} from './ReactFiberHooks';
function shouldProfile(current: Fiber): boolean {
return (
@@ -164,91 +158,19 @@ export function commitHookEffectListMount(
// Mount
let destroy;
if (enableUseEffectCRUDOverload) {
if (effect.resourceKind === ResourceEffectIdentityKind) {
if (__DEV__) {
effect.inst.resource = runWithFiberInDEV(
finishedWork,
callCreateInDEV,
effect,
);
if (effect.inst.resource == null) {
console.error(
'useEffect must provide a callback which returns a resource. ' +
'If a managed resource is not needed here, do not provide an updater or ' +
'destroy callback. Received %s',
effect.inst.resource,
);
}
} else {
effect.inst.resource = effect.create();
}
destroy = effect.inst.destroy;
}
if (effect.resourceKind === ResourceEffectUpdateKind) {
if (
// We don't want to fire updates on remount during Activity
(flags & HookHasEffect) > 0 &&
typeof effect.update === 'function' &&
effect.inst.resource != null
) {
// TODO(@poteto) what about multiple updates?
if (__DEV__) {
runWithFiberInDEV(finishedWork, callCreateInDEV, effect);
} else {
effect.update(effect.inst.resource);
}
}
}
}
if (__DEV__) {
if ((flags & HookInsertion) !== NoHookEffect) {
setIsRunningInsertionEffect(true);
}
if (enableUseEffectCRUDOverload) {
if (effect.resourceKind == null) {
destroy = runWithFiberInDEV(
finishedWork,
callCreateInDEV,
effect,
);
}
} else {
destroy = runWithFiberInDEV(
finishedWork,
callCreateInDEV,
effect,
);
}
destroy = runWithFiberInDEV(finishedWork, callCreateInDEV, effect);
if ((flags & HookInsertion) !== NoHookEffect) {
setIsRunningInsertionEffect(false);
}
} else {
if (enableUseEffectCRUDOverload) {
if (effect.resourceKind == null) {
const create = effect.create;
const inst = effect.inst;
destroy = create();
inst.destroy = destroy;
}
} else {
if (effect.resourceKind != null) {
if (__DEV__) {
console.error(
'Expected only SimpleEffects when enableUseEffectCRUDOverload is disabled, ' +
'got %s',
effect.resourceKind,
);
}
}
const create = effect.create;
const inst = effect.inst;
// $FlowFixMe[incompatible-type] (@poteto)
// $FlowFixMe[not-a-function] (@poteto)
destroy = create();
// $FlowFixMe[incompatible-type] (@poteto)
inst.destroy = destroy;
}
const create = effect.create;
const inst = effect.inst;
destroy = create();
inst.destroy = destroy;
}
if (enableSchedulingProfiler) {
@@ -338,13 +260,7 @@ export function commitHookEffectListUnmount(
const inst = effect.inst;
const destroy = inst.destroy;
if (destroy !== undefined) {
if (enableUseEffectCRUDOverload) {
if (effect.resourceKind == null) {
inst.destroy = undefined;
}
} else {
inst.destroy = undefined;
}
inst.destroy = undefined;
if (enableSchedulingProfiler) {
if ((flags & HookPassive) !== NoHookEffect) {
markComponentPassiveEffectUnmountStarted(finishedWork);
@@ -358,41 +274,7 @@ export function commitHookEffectListUnmount(
setIsRunningInsertionEffect(true);
}
}
if (enableUseEffectCRUDOverload) {
if (
effect.resourceKind === ResourceEffectIdentityKind &&
effect.inst.resource != null
) {
safelyCallDestroy(
finishedWork,
nearestMountedAncestor,
destroy,
effect.inst.resource,
);
if (effect.next.resourceKind === ResourceEffectUpdateKind) {
// $FlowFixMe[prop-missing] (@poteto)
effect.next.update = undefined;
} else {
if (__DEV__) {
console.error(
'Expected a ResourceEffectUpdateKind to follow ResourceEffectIdentityKind, ' +
'got %s. This is a bug in React.',
effect.next.resourceKind,
);
}
}
effect.inst.resource = null;
}
if (effect.resourceKind == null) {
safelyCallDestroy(
finishedWork,
nearestMountedAncestor,
destroy,
);
}
} else {
safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy);
}
safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy);
if (__DEV__) {
if ((flags & HookInsertion) !== NoHookEffect) {
setIsRunningInsertionEffect(false);
+46 -431
View File
@@ -43,7 +43,6 @@ import {
enableSchedulingProfiler,
enableTransitionTracing,
enableUseEffectEventHook,
enableUseEffectCRUDOverload,
enableLegacyCache,
disableLegacyMode,
enableNoCloningMemoCache,
@@ -219,43 +218,16 @@ export type Hook = {
// the additional memory and we can follow up with performance
// optimizations later.
type EffectInstance = {
resource: {...} | void | null,
destroy: void | (() => void) | ((resource: {...} | void | null) => void),
destroy: void | (() => void),
};
export const ResourceEffectIdentityKind: 0 = 0;
export const ResourceEffectUpdateKind: 1 = 1;
export type EffectKind =
| typeof ResourceEffectIdentityKind
| typeof ResourceEffectUpdateKind;
export type Effect =
| SimpleEffect
| ResourceEffectIdentity
| ResourceEffectUpdate;
export type SimpleEffect = {
export type Effect = {
tag: HookFlags,
inst: EffectInstance,
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
next: Effect,
};
export type ResourceEffectIdentity = {
resourceKind: typeof ResourceEffectIdentityKind,
tag: HookFlags,
inst: EffectInstance,
create: () => {...} | void | null,
deps: Array<mixed> | void | null,
next: Effect,
};
export type ResourceEffectUpdate = {
resourceKind: typeof ResourceEffectUpdateKind,
tag: HookFlags,
inst: EffectInstance,
update: ((resource: {...} | void | null) => void) | void,
deps: Array<mixed> | void | null,
next: Effect,
identity: ResourceEffectIdentity,
};
type StoreInstance<T> = {
value: T,
@@ -377,23 +349,6 @@ function checkDepsAreArrayDev(deps: mixed): void {
}
}
function checkDepsAreNonEmptyArrayDev(deps: mixed): void {
if (__DEV__) {
if (
deps !== undefined &&
deps !== null &&
isArray(deps) &&
deps.length === 0
) {
console.error(
'%s received a dependency array with no dependencies. When ' +
'specified, the dependency array must have at least one dependency.',
currentHookNameInDev,
);
}
}
}
function warnOnHookMismatchInDev(currentHookName: HookType): void {
if (__DEV__) {
const componentName = getComponentNameFromFiber(currentlyRenderingFiber);
@@ -2540,15 +2495,12 @@ function pushSimpleEffect(
tag: HookFlags,
inst: EffectInstance,
create: () => (() => void) | void,
createDeps: Array<mixed> | void | null,
update?: ((resource: {...} | void | null) => void) | void,
updateDeps?: Array<mixed> | void | null,
destroy?: ((resource: {...} | void | null) => void) | void,
deps: Array<mixed> | void | null,
): Effect {
const effect: Effect = {
tag,
create,
deps: createDeps,
deps,
inst,
// Circular
next: (null: any),
@@ -2556,39 +2508,6 @@ function pushSimpleEffect(
return pushEffectImpl(effect);
}
function pushResourceEffect(
identityTag: HookFlags,
updateTag: HookFlags,
inst: EffectInstance,
create: () => {...} | void | null,
createDeps: Array<mixed> | void | null,
update: ((resource: {...} | void | null) => void) | void,
updateDeps: Array<mixed> | void | null,
): Effect {
const effectIdentity: ResourceEffectIdentity = {
resourceKind: ResourceEffectIdentityKind,
tag: identityTag,
create,
deps: createDeps,
inst,
// Circular
next: (null: any),
};
pushEffectImpl(effectIdentity);
const effectUpdate: ResourceEffectUpdate = {
resourceKind: ResourceEffectUpdateKind,
tag: updateTag,
update,
deps: updateDeps,
inst,
identity: effectIdentity,
// Circular
next: (null: any),
};
return pushEffectImpl(effectUpdate);
}
function pushEffectImpl(effect: Effect): Effect {
let componentUpdateQueue: null | FunctionComponentUpdateQueue =
(currentlyRenderingFiber.updateQueue: any);
@@ -2609,7 +2528,7 @@ function pushEffectImpl(effect: Effect): Effect {
}
function createEffectInstance(): EffectInstance {
return {destroy: undefined, resource: undefined};
return {destroy: undefined};
}
function mountRef<T>(initialValue: T): {current: T} {
@@ -2628,13 +2547,10 @@ function mountEffectImpl(
fiberFlags: Flags,
hookFlags: HookFlags,
create: () => (() => void) | void,
createDeps: Array<mixed> | void | null,
update?: ((resource: {...} | void | null) => void) | void,
updateDeps?: Array<mixed> | void | null,
destroy?: ((resource: {...} | void | null) => void) | void,
deps: Array<mixed> | void | null,
): void {
const hook = mountWorkInProgressHook();
const nextDeps = createDeps === undefined ? null : createDeps;
const nextDeps = deps === undefined ? null : deps;
currentlyRenderingFiber.flags |= fiberFlags;
hook.memoizedState = pushSimpleEffect(
HookHasEffect | hookFlags,
@@ -2685,223 +2601,35 @@ function updateEffectImpl(
}
function mountEffect(
create: (() => (() => void) | void) | (() => {...} | void | null),
createDeps: Array<mixed> | void | null,
update?: ((resource: {...} | void | null) => void) | void,
updateDeps?: Array<mixed> | void | null,
destroy?: ((resource: {...} | void | null) => void) | void,
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
if (
__DEV__ &&
(currentlyRenderingFiber.mode & StrictEffectsMode) !== NoMode &&
(currentlyRenderingFiber.mode & NoStrictPassiveEffectsMode) === NoMode
) {
if (
enableUseEffectCRUDOverload &&
(typeof update === 'function' || typeof destroy === 'function')
) {
mountResourceEffectImpl(
MountPassiveDevEffect | PassiveEffect | PassiveStaticEffect,
HookPassive,
create,
createDeps,
update,
updateDeps,
destroy,
);
} else {
mountEffectImpl(
MountPassiveDevEffect | PassiveEffect | PassiveStaticEffect,
HookPassive,
// $FlowFixMe[incompatible-call] @poteto it's not possible to narrow `create` without calling it.
create,
createDeps,
);
}
mountEffectImpl(
MountPassiveDevEffect | PassiveEffect | PassiveStaticEffect,
HookPassive,
create,
deps,
);
} else {
if (
enableUseEffectCRUDOverload &&
(typeof update === 'function' || typeof destroy === 'function')
) {
mountResourceEffectImpl(
PassiveEffect | PassiveStaticEffect,
HookPassive,
create,
createDeps,
update,
updateDeps,
destroy,
);
} else {
mountEffectImpl(
PassiveEffect | PassiveStaticEffect,
HookPassive,
// $FlowFixMe[incompatible-call] @poteto it's not possible to narrow `create` without calling it.
create,
createDeps,
);
}
mountEffectImpl(
PassiveEffect | PassiveStaticEffect,
HookPassive,
create,
deps,
);
}
}
function updateEffect(
create: (() => (() => void) | void) | (() => {...} | void | null),
createDeps: Array<mixed> | void | null,
update?: ((resource: {...} | void | null) => void) | void,
updateDeps?: Array<mixed> | void | null,
destroy?: ((resource: {...} | void | null) => void) | void,
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
if (
enableUseEffectCRUDOverload &&
(typeof update === 'function' || typeof destroy === 'function')
) {
updateResourceEffectImpl(
PassiveEffect,
HookPassive,
create,
createDeps,
update,
updateDeps,
destroy,
);
} else {
// $FlowFixMe[incompatible-call] @poteto it's not possible to narrow `create` without calling it.
updateEffectImpl(PassiveEffect, HookPassive, create, createDeps);
}
}
function mountResourceEffect(
create: () => {...} | void | null,
createDeps: Array<mixed> | void | null,
update: ((resource: {...} | void | null) => void) | void,
updateDeps: Array<mixed> | void | null,
destroy: ((resource: {...} | void | null) => void) | void,
) {
if (
__DEV__ &&
(currentlyRenderingFiber.mode & StrictEffectsMode) !== NoMode &&
(currentlyRenderingFiber.mode & NoStrictPassiveEffectsMode) === NoMode
) {
} else {
mountResourceEffectImpl(
PassiveEffect | PassiveStaticEffect,
HookPassive,
create,
createDeps,
update,
updateDeps,
destroy,
);
}
}
function mountResourceEffectImpl(
fiberFlags: Flags,
hookFlags: HookFlags,
create: () => {...} | void | null,
createDeps: Array<mixed> | void | null,
update: ((resource: {...} | void | null) => void) | void,
updateDeps: Array<mixed> | void | null,
destroy: ((resource: {...} | void | null) => void) | void,
) {
const hook = mountWorkInProgressHook();
currentlyRenderingFiber.flags |= fiberFlags;
const inst = createEffectInstance();
inst.destroy = destroy;
hook.memoizedState = pushResourceEffect(
HookHasEffect | hookFlags,
hookFlags,
inst,
create,
createDeps,
update,
updateDeps,
);
}
function updateResourceEffect(
create: () => {...} | void | null,
createDeps: Array<mixed> | void | null,
update: ((resource: {...} | void | null) => void) | void,
updateDeps: Array<mixed> | void | null,
destroy: ((resource: {...} | void | null) => void) | void,
) {
updateResourceEffectImpl(
PassiveEffect,
HookPassive,
create,
createDeps,
update,
updateDeps,
destroy,
);
}
function updateResourceEffectImpl(
fiberFlags: Flags,
hookFlags: HookFlags,
create: () => {...} | void | null,
createDeps: Array<mixed> | void | null,
update: ((resource: {...} | void | null) => void) | void,
updateDeps: Array<mixed> | void | null,
destroy: ((resource: {...} | void | null) => void) | void,
) {
const hook = updateWorkInProgressHook();
const effect: Effect = hook.memoizedState;
const inst = effect.inst;
inst.destroy = destroy;
const nextCreateDeps = createDeps === undefined ? null : createDeps;
const nextUpdateDeps = updateDeps === undefined ? null : updateDeps;
let isCreateDepsSame: boolean;
let isUpdateDepsSame: boolean;
if (currentHook !== null) {
const prevEffect: Effect = currentHook.memoizedState;
if (nextCreateDeps !== null) {
let prevCreateDeps;
if (
prevEffect.resourceKind != null &&
prevEffect.resourceKind === ResourceEffectUpdateKind
) {
prevCreateDeps =
prevEffect.identity.deps != null ? prevEffect.identity.deps : null;
} else {
throw new Error(
`Expected a ResourceEffectUpdate to be pushed together with ResourceEffectIdentity. This is a bug in React.`,
);
}
isCreateDepsSame = areHookInputsEqual(nextCreateDeps, prevCreateDeps);
}
if (nextUpdateDeps !== null) {
let prevUpdateDeps;
if (
prevEffect.resourceKind != null &&
prevEffect.resourceKind === ResourceEffectUpdateKind
) {
prevUpdateDeps = prevEffect.deps != null ? prevEffect.deps : null;
} else {
throw new Error(
`Expected a ResourceEffectUpdate to be pushed together with ResourceEffectIdentity. This is a bug in React.`,
);
}
isUpdateDepsSame = areHookInputsEqual(nextUpdateDeps, prevUpdateDeps);
}
}
if (!(isCreateDepsSame && isUpdateDepsSame)) {
currentlyRenderingFiber.flags |= fiberFlags;
}
hook.memoizedState = pushResourceEffect(
isCreateDepsSame ? hookFlags : HookHasEffect | hookFlags,
isUpdateDepsSame ? hookFlags : HookHasEffect | hookFlags,
inst,
create,
nextCreateDeps,
update,
nextUpdateDeps,
);
updateEffectImpl(PassiveEffect, HookPassive, create, deps);
}
function useEffectEventImpl<Args, Return, F: (...Array<Args>) => Return>(
@@ -4339,30 +4067,13 @@ if (__DEV__) {
return readContext(context);
},
useEffect(
create: (() => (() => void) | void) | (() => {...} | void | null),
createDeps: Array<mixed> | void | null,
update?: ((resource: {...} | void | null) => void) | void,
updateDeps?: Array<mixed> | void | null,
destroy?: ((resource: {...} | void | null) => void) | void,
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useEffect';
mountHookTypesDev();
if (
enableUseEffectCRUDOverload &&
(typeof update === 'function' || typeof destroy === 'function')
) {
checkDepsAreNonEmptyArrayDev(updateDeps);
return mountResourceEffect(
create,
createDeps,
update,
updateDeps,
destroy,
);
} else {
checkDepsAreArrayDev(createDeps);
return mountEffect(create, createDeps);
}
checkDepsAreArrayDev(deps);
return mountEffect(create, deps);
},
useImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
@@ -4540,28 +4251,12 @@ if (__DEV__) {
return readContext(context);
},
useEffect(
create: (() => (() => void) | void) | (() => {...} | void | null),
createDeps: Array<mixed> | void | null,
update?: ((resource: {...} | void | null) => void) | void,
updateDeps?: Array<mixed> | void | null,
destroy?: ((resource: {...} | void | null) => void) | void,
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useEffect';
updateHookTypesDev();
if (
enableUseEffectCRUDOverload &&
(typeof update === 'function' || typeof destroy === 'function')
) {
return mountResourceEffect(
create,
createDeps,
update,
updateDeps,
destroy,
);
} else {
return mountEffect(create, createDeps);
}
return mountEffect(create, deps);
},
useImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
@@ -4735,28 +4430,12 @@ if (__DEV__) {
return readContext(context);
},
useEffect(
create: (() => (() => void) | void) | (() => {...} | void | null),
createDeps: Array<mixed> | void | null,
update?: ((resource: {...} | void | null) => void) | void,
updateDeps?: Array<mixed> | void | null,
destroy?: ((resource: {...} | void | null) => void) | void,
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useEffect';
updateHookTypesDev();
if (
enableUseEffectCRUDOverload &&
(typeof update === 'function' || typeof destroy === 'function')
) {
return updateResourceEffect(
create,
createDeps,
update,
updateDeps,
destroy,
);
} else {
return updateEffect(create, createDeps);
}
return updateEffect(create, deps);
},
useImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
@@ -4930,28 +4609,12 @@ if (__DEV__) {
return readContext(context);
},
useEffect(
create: (() => (() => void) | void) | (() => {...} | void | null),
createDeps: Array<mixed> | void | null,
update?: ((resource: {...} | void | null) => void) | void,
updateDeps?: Array<mixed> | void | null,
destroy?: ((resource: {...} | void | null) => void) | void,
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useEffect';
updateHookTypesDev();
if (
enableUseEffectCRUDOverload &&
(typeof update === 'function' || typeof destroy === 'function')
) {
return updateResourceEffect(
create,
createDeps,
update,
updateDeps,
destroy,
);
} else {
return updateEffect(create, createDeps);
}
return updateEffect(create, deps);
},
useImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
@@ -5131,29 +4794,13 @@ if (__DEV__) {
return readContext(context);
},
useEffect(
create: (() => (() => void) | void) | (() => {...} | void | null),
createDeps: Array<mixed> | void | null,
update?: ((resource: {...} | void | null) => void) | void,
updateDeps?: Array<mixed> | void | null,
destroy?: ((resource: {...} | void | null) => void) | void,
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useEffect';
warnInvalidHookAccess();
mountHookTypesDev();
if (
enableUseEffectCRUDOverload &&
(typeof update === 'function' || typeof destroy === 'function')
) {
return mountResourceEffect(
create,
createDeps,
update,
updateDeps,
destroy,
);
} else {
return mountEffect(create, createDeps);
}
return mountEffect(create, deps);
},
useImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
@@ -5352,29 +4999,13 @@ if (__DEV__) {
return readContext(context);
},
useEffect(
create: (() => (() => void) | void) | (() => {...} | void | null),
createDeps: Array<mixed> | void | null,
update?: ((resource: {...} | void | null) => void) | void,
updateDeps?: Array<mixed> | void | null,
destroy?: ((resource: {...} | void | null) => void) | void,
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useEffect';
warnInvalidHookAccess();
updateHookTypesDev();
if (
enableUseEffectCRUDOverload &&
(typeof update === 'function' || typeof destroy === 'function')
) {
return updateResourceEffect(
create,
createDeps,
update,
updateDeps,
destroy,
);
} else {
return updateEffect(create, createDeps);
}
return updateEffect(create, deps);
},
useImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
@@ -5573,29 +5204,13 @@ if (__DEV__) {
return readContext(context);
},
useEffect(
create: (() => (() => void) | void) | (() => {...} | void | null),
createDeps: Array<mixed> | void | null,
update?: ((resource: {...} | void | null) => void) | void,
updateDeps?: Array<mixed> | void | null,
destroy?: ((resource: {...} | void | null) => void) | void,
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
currentHookNameInDev = 'useEffect';
warnInvalidHookAccess();
updateHookTypesDev();
if (
enableUseEffectCRUDOverload &&
(typeof update === 'function' || typeof destroy === 'function')
) {
return updateResourceEffect(
create,
createDeps,
update,
updateDeps,
destroy,
);
} else {
return updateEffect(create, createDeps);
}
return updateEffect(create, deps);
},
useImperativeHandle<T>(
ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
+2 -5
View File
@@ -399,11 +399,8 @@ export type Dispatcher = {
useContext<T>(context: ReactContext<T>): T,
useRef<T>(initialValue: T): {current: T},
useEffect(
create: (() => (() => void) | void) | (() => {...} | void | null),
createDeps: Array<mixed> | void | null,
update?: ((resource: {...} | void | null) => void) | void,
updateDeps?: Array<mixed> | void | null,
destroy?: ((resource: {...} | void | null) => void) | void,
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void,
// TODO: Non-nullable once `enableUseEffectEventHook` is on everywhere.
useEffectEvent?: <Args, F: (...Array<Args>) => mixed>(callback: F) => F,
@@ -3309,760 +3309,6 @@ describe('ReactHooksWithNoopRenderer', () => {
});
});
// @gate enableUseEffectCRUDOverload
describe('useEffect CRUD overload', () => {
class Resource {
isDeleted: false;
id: string;
opts: mixed;
constructor(id, opts) {
this.id = id;
this.opts = opts;
}
update(opts) {
if (this.isDeleted) {
console.error('Cannot update deleted resource');
return;
}
this.opts = opts;
}
destroy() {
this.isDeleted = true;
}
}
// @gate !enableUseEffectCRUDOverload
it('is null when flag is disabled', async () => {
function App({id}) {
useEffect(
() => {
Scheduler.log(`create(${id})`);
return {};
},
[id],
() => {
Scheduler.log('update');
},
[],
);
return null;
}
await expect(async () => {
await act(() => {
ReactNoop.render(<App id={1} />);
});
}).rejects.toThrow(
'useEffect CRUD overload is not enabled in this build of React.',
);
});
// @gate enableUseEffectCRUDOverload
it('validates non-empty update deps', async () => {
function App({id}) {
useEffect(
() => {
Scheduler.log(`create(${id})`);
return {};
},
[id],
() => {
Scheduler.log('update');
},
[],
);
return null;
}
await act(() => {
ReactNoop.render(<App id={1} />);
});
assertConsoleErrorDev([
'useEffect received a dependency array with no dependencies. ' +
'When specified, the dependency array must have at least one dependency.\n' +
' in App (at **)',
]);
});
// @gate enableUseEffectCRUDOverload
it('simple mount and update', async () => {
function App({id, username}) {
const opts = useMemo(() => {
return {username};
}, [username]);
useEffect(
() => {
const resource = new Resource(id, opts);
Scheduler.log(`create(${resource.id}, ${resource.opts.username})`);
return resource;
},
[id],
resource => {
resource.update(opts);
Scheduler.log(`update(${resource.id}, ${resource.opts.username})`);
},
[opts],
resource => {
resource.destroy();
Scheduler.log(`destroy(${resource.id}, ${resource.opts.username})`);
},
);
return null;
}
await act(() => {
ReactNoop.render(<App id={1} username="Jack" />);
});
assertLog(['create(1, Jack)']);
await act(() => {
ReactNoop.render(<App id={1} username="Lauren" />);
});
assertLog(['update(1, Lauren)']);
await act(() => {
ReactNoop.render(<App id={1} username="Lauren" />);
});
assertLog([]);
await act(() => {
ReactNoop.render(<App id={1} username="Jordan" />);
});
assertLog(['update(1, Jordan)']);
await act(() => {
ReactNoop.render(<App id={2} username="Jack" />);
});
assertLog(['destroy(1, Jordan)', 'create(2, Jack)']);
await act(() => {
ReactNoop.render(null);
});
assertLog(['destroy(2, Jack)']);
});
// @gate enableUseEffectCRUDOverload
it('simple mount with no update', async () => {
function App({id, username}) {
const opts = useMemo(() => {
return {username};
}, [username]);
useEffect(
() => {
const resource = new Resource(id, opts);
Scheduler.log(`create(${resource.id}, ${resource.opts.username})`);
return resource;
},
[id],
resource => {
resource.update(opts);
Scheduler.log(`update(${resource.id}, ${resource.opts.username})`);
},
[opts],
resource => {
resource.destroy();
Scheduler.log(`destroy(${resource.id}, ${resource.opts.username})`);
},
);
return null;
}
await act(() => {
ReactNoop.render(<App id={1} username="Jack" />);
});
assertLog(['create(1, Jack)']);
await act(() => {
ReactNoop.render(null);
});
assertLog(['destroy(1, Jack)']);
});
// @gate enableUseEffectCRUDOverload
it('calls update on every render if no deps are specified', async () => {
function App({id, username}) {
const opts = useMemo(() => {
return {username};
}, [username]);
useEffect(
() => {
const resource = new Resource(id, opts);
Scheduler.log(`create(${resource.id}, ${resource.opts.username})`);
return resource;
},
[id],
resource => {
resource.update(opts);
Scheduler.log(`update(${resource.id}, ${resource.opts.username})`);
},
);
return null;
}
await act(() => {
ReactNoop.render(<App id={1} username="Jack" />);
});
assertLog(['create(1, Jack)']);
await act(() => {
ReactNoop.render(<App id={1} username="Jack" />);
});
assertLog(['update(1, Jack)']);
await act(() => {
ReactNoop.render(<App id={2} username="Jack" />);
});
assertLog(['create(2, Jack)', 'update(2, Jack)']);
await act(() => {
ReactNoop.render(<App id={2} username="Lauren" />);
});
assertLog(['update(2, Lauren)']);
});
// @gate enableUseEffectCRUDOverload
it('does not unmount previous useEffect between updates', async () => {
function App({id}) {
useEffect(
() => {
const resource = new Resource(id);
Scheduler.log(`create(${resource.id})`);
return resource;
},
[],
resource => {
Scheduler.log(`update(${resource.id})`);
},
undefined,
resource => {
Scheduler.log(`destroy(${resource.id})`);
resource.destroy();
},
);
return <Text text={'Id: ' + id} />;
}
await act(async () => {
ReactNoop.render(<App id={0} />, () => Scheduler.log('Sync effect'));
await waitFor(['Id: 0', 'Sync effect']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Id: 0" />);
});
assertLog(['create(0)']);
await act(async () => {
ReactNoop.render(<App id={1} />, () => Scheduler.log('Sync effect'));
await waitFor(['Id: 1', 'Sync effect']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Id: 1" />);
});
assertLog(['update(0)']);
});
// @gate enableUseEffectCRUDOverload
it('unmounts only on deletion', async () => {
function App({id}) {
useEffect(
() => {
const resource = new Resource(id);
Scheduler.log(`create(${resource.id})`);
return resource;
},
undefined,
resource => {
Scheduler.log(`update(${resource.id})`);
},
undefined,
resource => {
Scheduler.log(`destroy(${resource.id})`);
resource.destroy();
},
);
return <Text text={'Id: ' + id} />;
}
await act(async () => {
ReactNoop.render(<App id={0} />, () => Scheduler.log('Sync effect'));
await waitFor(['Id: 0', 'Sync effect']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Id: 0" />);
});
assertLog(['create(0)']);
ReactNoop.render(null);
await waitForAll(['destroy(0)']);
expect(ReactNoop).toMatchRenderedOutput(null);
});
// @gate enableUseEffectCRUDOverload
it('unmounts on deletion', async () => {
function Wrapper(props) {
return <App {...props} />;
}
function App({id, username}) {
const opts = useMemo(() => {
return {username};
}, [username]);
useEffect(
() => {
const resource = new Resource(id, opts);
Scheduler.log(`create(${resource.id}, ${resource.opts.username})`);
return resource;
},
[id],
resource => {
resource.update(opts);
Scheduler.log(`update(${resource.id}, ${resource.opts.username})`);
},
[opts],
resource => {
resource.destroy();
Scheduler.log(`destroy(${resource.id}, ${resource.opts.username})`);
},
);
return <Text text={'Id: ' + id} />;
}
await act(async () => {
ReactNoop.render(<Wrapper id={0} username="Sathya" />, () =>
Scheduler.log('Sync effect'),
);
await waitFor(['Id: 0', 'Sync effect']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Id: 0" />);
});
assertLog(['create(0, Sathya)']);
await act(async () => {
ReactNoop.render(<Wrapper id={0} username="Lauren" />, () =>
Scheduler.log('Sync effect'),
);
await waitFor(['Id: 0', 'Sync effect']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Id: 0" />);
});
assertLog(['update(0, Lauren)']);
ReactNoop.render(null);
await waitForAll(['destroy(0, Lauren)']);
expect(ReactNoop).toMatchRenderedOutput(null);
});
// @gate enableUseEffectCRUDOverload
it('handles errors in create on mount', async () => {
function App({id}) {
useEffect(
() => {
Scheduler.log(`Mount A [${id}]`);
return {};
},
undefined,
undefined,
undefined,
resource => {
Scheduler.log(`Unmount A [${id}]`);
},
);
useEffect(
() => {
Scheduler.log('Oops!');
throw new Error('Oops!');
// eslint-disable-next-line no-unreachable
Scheduler.log(`Mount B [${id}]`);
return {};
},
undefined,
undefined,
undefined,
resource => {
Scheduler.log(`Unmount B [${id}]`);
},
);
return <Text text={'Id: ' + id} />;
}
await expect(async () => {
await act(async () => {
ReactNoop.render(<App id={0} />, () => Scheduler.log('Sync effect'));
await waitFor(['Id: 0', 'Sync effect']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Id: 0" />);
});
}).rejects.toThrow('Oops');
assertLog([
'Mount A [0]',
'Oops!',
// Clean up effect A. There's no effect B to clean-up, because it
// never mounted.
'Unmount A [0]',
]);
expect(ReactNoop).toMatchRenderedOutput(null);
});
// @gate enableUseEffectCRUDOverload
it('handles errors in create on update', async () => {
function App({id}) {
useEffect(
() => {
Scheduler.log(`Mount A [${id}]`);
return {};
},
[],
() => {
if (id === 1) {
Scheduler.log('Oops!');
throw new Error('Oops error!');
}
Scheduler.log(`Update A [${id}]`);
},
[id],
() => {
Scheduler.log(`Unmount A [${id}]`);
},
);
return <Text text={'Id: ' + id} />;
}
await act(async () => {
ReactNoop.render(<App id={0} />, () => Scheduler.log('Sync effect'));
await waitFor(['Id: 0', 'Sync effect']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Id: 0" />);
ReactNoop.flushPassiveEffects();
assertLog(['Mount A [0]']);
});
await expect(async () => {
await act(async () => {
// This update will trigger an error
ReactNoop.render(<App id={1} />, () => Scheduler.log('Sync effect'));
await waitFor(['Id: 1', 'Sync effect']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Id: 1" />);
ReactNoop.flushPassiveEffects();
assertLog(['Oops!', 'Unmount A [1]']);
expect(ReactNoop).toMatchRenderedOutput(null);
});
}).rejects.toThrow('Oops error!');
});
// @gate enableUseEffectCRUDOverload
it('handles errors in destroy on update', async () => {
function App({id, username}) {
const opts = useMemo(() => {
return {username};
}, [username]);
useEffect(
() => {
const resource = new Resource(id, opts);
Scheduler.log(`Mount A [${id}, ${resource.opts.username}]`);
return resource;
},
[id],
resource => {
resource.update(opts);
Scheduler.log(`Update A [${id}, ${resource.opts.username}]`);
},
[opts],
resource => {
Scheduler.log(`Oops, ${resource.opts.username}!`);
if (id === 1) {
throw new Error(`Oops ${resource.opts.username} error!`);
}
Scheduler.log(`Unmount A [${id}, ${resource.opts.username}]`);
},
);
return <Text text={'Id: ' + id} />;
}
await act(async () => {
ReactNoop.render(<App id={0} username="Lauren" />, () =>
Scheduler.log('Sync effect'),
);
await waitFor(['Id: 0', 'Sync effect']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Id: 0" />);
ReactNoop.flushPassiveEffects();
assertLog(['Mount A [0, Lauren]']);
});
await expect(async () => {
await act(async () => {
// This update will trigger an error during passive effect unmount
ReactNoop.render(<App id={1} username="Sathya" />, () =>
Scheduler.log('Sync effect'),
);
await waitFor(['Id: 1', 'Sync effect']);
expect(ReactNoop).toMatchRenderedOutput(<span prop="Id: 1" />);
ReactNoop.flushPassiveEffects();
assertLog(['Oops, Lauren!', 'Mount A [1, Sathya]', 'Oops, Sathya!']);
});
// TODO(lauren) more explicit assertions. this is weird because we
// destroy both the first and second resource
}).rejects.toThrow();
expect(ReactNoop).toMatchRenderedOutput(null);
});
// @gate enableUseEffectCRUDOverload && enableActivity
it('composes with activity', async () => {
function App({id, username}) {
const opts = useMemo(() => {
return {username};
}, [username]);
useEffect(
() => {
const resource = new Resource(id, opts);
Scheduler.log(`create(${resource.id}, ${resource.opts.username})`);
return resource;
},
[id],
resource => {
resource.update(opts);
Scheduler.log(`update(${resource.id}, ${resource.opts.username})`);
},
[opts],
resource => {
resource.destroy();
Scheduler.log(`destroy(${resource.id}, ${resource.opts.username})`);
},
);
return null;
}
const root = ReactNoop.createRoot();
await act(() => {
root.render(
<Activity mode="hidden">
<App id={0} username="Rick" />
</Activity>,
);
});
assertLog([]);
await act(() => {
root.render(
<Activity mode="hidden">
<App id={0} username="Lauren" />
</Activity>,
);
});
assertLog([]);
await act(() => {
root.render(
<Activity mode="visible">
<App id={0} username="Rick" />
</Activity>,
);
});
assertLog(['create(0, Rick)']);
await act(() => {
root.render(
<Activity mode="visible">
<App id={0} username="Lauren" />
</Activity>,
);
});
assertLog(['update(0, Lauren)']);
await act(() => {
root.render(
<Activity mode="hidden">
<App id={0} username="Lauren" />
</Activity>,
);
});
assertLog(['destroy(0, Lauren)']);
});
// @gate enableUseEffectCRUDOverload
it('composes with suspense', async () => {
function TextBox({text}) {
return <AsyncText text={text} ms={0} />;
}
let setUsername_;
function App({id}) {
const [username, setUsername] = useState('Mofei');
setUsername_ = setUsername;
const opts = useMemo(() => {
return {username};
}, [username]);
useEffect(
() => {
const resource = new Resource(id, opts);
Scheduler.log(`create(${resource.id}, ${resource.opts.username})`);
return resource;
},
[id],
resource => {
resource.update(opts);
Scheduler.log(`update(${resource.id}, ${resource.opts.username})`);
},
[opts],
resource => {
resource.destroy();
Scheduler.log(`destroy(${resource.id}, ${resource.opts.username})`);
},
);
return (
<>
<Text text={'Sync: ' + username} />
<Suspense fallback={<Text text={'Loading'} />}>
<TextBox text={username} />
</Suspense>
</>
);
}
await act(async () => {
ReactNoop.render(<App id={0} />);
await waitFor([
'Sync: Mofei',
'Suspend! [Mofei]',
'Loading',
'create(0, Mofei)',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
<span prop="Sync: Mofei" />
<span prop="Loading" />
</>,
);
ReactNoop.flushPassiveEffects();
assertLog([]);
Scheduler.unstable_advanceTime(10);
await advanceTimers(10);
assertLog(['Promise resolved [Mofei]']);
});
assertLog(['Mofei']);
expect(ReactNoop).toMatchRenderedOutput(
<>
<span prop="Sync: Mofei" />
<span prop="Mofei" />
</>,
);
await act(async () => {
ReactNoop.render(<App id={1} />, () => Scheduler.log('Sync effect'));
await waitFor([
'Sync: Mofei',
'Mofei',
'Sync effect',
'destroy(0, Mofei)',
'create(1, Mofei)',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
<span prop="Sync: Mofei" />
<span prop="Mofei" />
</>,
);
ReactNoop.flushPassiveEffects();
assertLog([]);
});
await act(async () => {
setUsername_('Lauren');
await waitFor([
'Sync: Lauren',
'Suspend! [Lauren]',
'Loading',
'update(1, Lauren)',
]);
expect(ReactNoop).toMatchRenderedOutput(
<>
<span prop="Sync: Lauren" />
<span hidden={true} prop="Mofei" />
<span prop="Loading" />
</>,
);
ReactNoop.flushPassiveEffects();
assertLog([]);
Scheduler.unstable_advanceTime(10);
await advanceTimers(10);
assertLog(['Promise resolved [Lauren]']);
});
assertLog(['Lauren']);
expect(ReactNoop).toMatchRenderedOutput(
<>
<span prop="Sync: Lauren" />
<span prop="Lauren" />
</>,
);
});
// @gate enableUseEffectCRUDOverload
it('composes with other kinds of effects', async () => {
let rerender;
function App({id, username}) {
const [count, rerender_] = useState(0);
rerender = rerender_;
const opts = useMemo(() => {
return {username};
}, [username]);
useEffect(() => {
Scheduler.log(`useEffect(${count})`);
}, [count]);
useEffect(
() => {
const resource = new Resource(id, opts);
Scheduler.log(`create(${resource.id}, ${resource.opts.username})`);
return resource;
},
[id],
resource => {
resource.update(opts);
Scheduler.log(`update(${resource.id}, ${resource.opts.username})`);
},
[opts],
resource => {
resource.destroy();
Scheduler.log(`destroy(${resource.id}, ${resource.opts.username})`);
},
);
return null;
}
await act(() => {
ReactNoop.render(<App id={1} username="Jack" />);
});
assertLog(['useEffect(0)', 'create(1, Jack)']);
await act(() => {
ReactNoop.render(<App id={1} username="Lauren" />);
});
assertLog(['update(1, Lauren)']);
await act(() => {
ReactNoop.render(<App id={1} username="Lauren" />);
});
assertLog([]);
await act(() => {
ReactNoop.render(<App id={1} username="Jordan" />);
});
assertLog(['update(1, Jordan)']);
await act(() => {
rerender(n => n + 1);
});
assertLog(['useEffect(1)']);
await act(() => {
ReactNoop.render(<App id={1} username="Mofei" />);
});
assertLog(['update(1, Mofei)']);
await act(() => {
ReactNoop.render(<App id={2} username="Jack" />);
});
assertLog(['destroy(1, Mofei)', 'create(2, Jack)']);
await act(() => {
ReactNoop.render(null);
});
assertLog(['destroy(2, Jack)']);
});
});
describe('useCallback', () => {
it('memoizes callback by comparing inputs', async () => {
class IncrementButton extends React.PureComponent {
+4 -27
View File
@@ -19,10 +19,7 @@ import {REACT_CONSUMER_TYPE} from 'shared/ReactSymbols';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import {
enableUseEffectCRUDOverload,
enableSwipeTransition,
} from 'shared/ReactFeatureFlags';
import {enableSwipeTransition} from 'shared/ReactFeatureFlags';
type BasicStateAction<S> = (S => S) | S;
type Dispatch<A> = A => void;
@@ -91,11 +88,8 @@ export function useRef<T>(initialValue: T): {current: T} {
}
export function useEffect(
create: (() => (() => void) | void) | (() => {...} | void | null),
createDeps: Array<mixed> | void | null,
update?: ((resource: {...} | void | null) => void) | void,
updateDeps?: Array<mixed> | void | null,
destroy?: ((resource: {...} | void | null) => void) | void,
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
if (__DEV__) {
if (create == null) {
@@ -106,24 +100,7 @@ export function useEffect(
}
const dispatcher = resolveDispatcher();
if (
enableUseEffectCRUDOverload &&
(typeof update === 'function' || typeof destroy === 'function')
) {
// $FlowFixMe[not-a-function] This is unstable, thus optional
return dispatcher.useEffect(
create,
createDeps,
update,
updateDeps,
destroy,
);
} else if (typeof update === 'function') {
throw new Error(
'useEffect CRUD overload is not enabled in this build of React.',
);
}
return dispatcher.useEffect(create, createDeps);
return dispatcher.useEffect(create, deps);
}
export function useInsertionEffect(
-5
View File
@@ -154,11 +154,6 @@ export const transitionLaneExpirationMs = 5000;
*/
export const enableInfiniteRenderLoopDetection = false;
/**
* Experimental new hook for better managing resources in effects.
*/
export const enableUseEffectCRUDOverload = false;
export const enableFastAddPropertiesInDiffing = true;
export const enableLazyPublicInstanceInFabric = false;
@@ -25,7 +25,6 @@ export const enableShallowPropDiffing = __VARIANT__;
export const passChildrenWhenCloningPersistedNodes = __VARIANT__;
export const enableFabricCompleteRootInCommitPhase = __VARIANT__;
export const enableSiblingPrerendering = __VARIANT__;
export const enableUseEffectCRUDOverload = __VARIANT__;
export const enableFastAddPropertiesInDiffing = __VARIANT__;
export const enableLazyPublicInstanceInFabric = __VARIANT__;
export const renameElementSymbol = __VARIANT__;
@@ -25,7 +25,6 @@ export const {
enableObjectFiber,
enablePersistedModeClonedFlag,
enableShallowPropDiffing,
enableUseEffectCRUDOverload,
passChildrenWhenCloningPersistedNodes,
enableSiblingPrerendering,
enableFastAddPropertiesInDiffing,
@@ -63,7 +63,6 @@ export const retryLaneExpirationMs = 5000;
export const syncLaneExpirationMs = 250;
export const transitionLaneExpirationMs = 5000;
export const enableSiblingPrerendering = true;
export const enableUseEffectCRUDOverload = false;
export const enableHydrationLaneScheduling = true;
@@ -65,8 +65,6 @@ export const renameElementSymbol = true;
export const enableShallowPropDiffing = false;
export const enableSiblingPrerendering = true;
export const enableUseEffectCRUDOverload = false;
export const enableYieldingBeforePassive = true;
export const enableThrottledScheduling = false;
@@ -62,7 +62,6 @@ export const syncLaneExpirationMs = 250;
export const transitionLaneExpirationMs = 5000;
export const enableFabricCompleteRootInCommitPhase = false;
export const enableSiblingPrerendering = true;
export const enableUseEffectCRUDOverload = true;
export const enableHydrationLaneScheduling = true;
export const enableYieldingBeforePassive = false;
export const enableThrottledScheduling = false;
@@ -74,8 +74,6 @@ export const enableObjectFiber = false;
export const enableShallowPropDiffing = false;
export const enableSiblingPrerendering = true;
export const enableUseEffectCRUDOverload = false;
export const enableHydrationLaneScheduling = true;
export const enableYieldingBeforePassive = false;
@@ -35,7 +35,6 @@ export const enableSchedulingProfiler = __VARIANT__;
export const enableInfiniteRenderLoopDetection = __VARIANT__;
export const enableSiblingPrerendering = __VARIANT__;
export const enableUseEffectCRUDOverload = __VARIANT__;
export const enableFastAddPropertiesInDiffing = __VARIANT__;
export const enableLazyPublicInstanceInFabric = false;
export const enableViewTransition = __VARIANT__;
@@ -29,7 +29,6 @@ export const {
enableSiblingPrerendering,
enableTransitionTracing,
enableTrustedTypesIntegration,
enableUseEffectCRUDOverload,
favorSafetyOverHydrationPerf,
renameElementSymbol,
retryLaneExpirationMs,