Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add StrictMode level prop and createRoot unstable_strictModeLevel option #20849

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion packages/react-dom/src/client/ReactDOMRoot.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export type RootOptions = {
mutableSources?: Array<MutableSource<any>>,
...
},
unstable_strictModeLevel?: number,
...
};

Expand Down Expand Up @@ -128,7 +129,18 @@ function createRootImpl(
options.hydrationOptions != null &&
options.hydrationOptions.mutableSources) ||
null;
const root = createContainer(container, tag, hydrate, hydrationCallbacks);
const strictModeLevelOverride =
options != null && options.unstable_strictModeLevel != null
bvaughn marked this conversation as resolved.
Show resolved Hide resolved
? options.unstable_strictModeLevel
: null;

const root = createContainer(
container,
tag,
hydrate,
hydrationCallbacks,
strictModeLevelOverride,
);
markContainerAsRoot(root.current, container);

const rootContainerElement =
Expand Down
2 changes: 1 addition & 1 deletion packages/react-native-renderer/src/ReactFabric.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ function render(
if (!root) {
// TODO (bvaughn): If we decide to keep the wrapper component,
// We could create a wrapper for containerTag as well to reduce special casing.
root = createContainer(containerTag, LegacyRoot, false, null);
root = createContainer(containerTag, LegacyRoot, false, null, null);
roots.set(containerTag, root);
}
updateContainer(element, root, null, callback);
Expand Down
2 changes: 1 addition & 1 deletion packages/react-native-renderer/src/ReactNativeRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ function render(
if (!root) {
// TODO (bvaughn): If we decide to keep the wrapper component,
// We could create a wrapper for containerTag as well to reduce special casing.
root = createContainer(containerTag, LegacyRoot, false, null);
root = createContainer(containerTag, LegacyRoot, false, null, null);
roots.set(containerTag, root);
}
updateContainer(element, root, null, callback);
Expand Down
5 changes: 4 additions & 1 deletion packages/react-noop-renderer/src/createReactNoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
if (!root) {
const container = {rootID: rootID, pendingChildren: [], children: []};
rootContainers.set(rootID, container);
root = NoopRenderer.createContainer(container, tag, false, null);
root = NoopRenderer.createContainer(container, tag, false, null, null);
roots.set(rootID, root);
}
return root.current.stateNode.containerInfo;
Expand All @@ -740,6 +740,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
ConcurrentRoot,
false,
null,
null,
);
return {
_Scheduler: Scheduler,
Expand All @@ -766,6 +767,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
BlockingRoot,
false,
null,
null,
);
return {
_Scheduler: Scheduler,
Expand All @@ -792,6 +794,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
LegacyRoot,
false,
null,
null,
);
return {
_Scheduler: Scheduler,
Expand Down
4 changes: 2 additions & 2 deletions packages/react-reconciler/src/ReactChildFiber.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import {
} from './ReactFiber.new';
import {emptyRefsObject} from './ReactFiberClassComponent.new';
import {isCompatibleFamilyForHotReloading} from './ReactFiberHotReloading.new';
import {StrictMode} from './ReactTypeOfMode';
import {StrictLegacyMode} from './ReactTypeOfMode';

let didWarnAboutMaps;
let didWarnAboutGenerators;
Expand Down Expand Up @@ -114,7 +114,7 @@ function coerceRef(
// TODO: Clean this up once we turn on the string ref warning for
// everyone, because the strict mode case will no longer be relevant
if (
(returnFiber.mode & StrictMode || warnAboutStringRefs) &&
(returnFiber.mode & StrictLegacyMode || warnAboutStringRefs) &&
// We warn in ReactElement.js if owner and self are equal for string refs
// because these cannot be automatically converted to an arrow function
// using a codemod. Therefore, we don't have to warn about string refs again.
Expand Down
4 changes: 2 additions & 2 deletions packages/react-reconciler/src/ReactChildFiber.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import {
} from './ReactFiber.old';
import {emptyRefsObject} from './ReactFiberClassComponent.old';
import {isCompatibleFamilyForHotReloading} from './ReactFiberHotReloading.old';
import {StrictMode} from './ReactTypeOfMode';
import {StrictLegacyMode} from './ReactTypeOfMode';

let didWarnAboutMaps;
let didWarnAboutGenerators;
Expand Down Expand Up @@ -114,7 +114,7 @@ function coerceRef(
// TODO: Clean this up once we turn on the string ref warning for
// everyone, because the strict mode case will no longer be relevant
if (
(returnFiber.mode & StrictMode || warnAboutStringRefs) &&
(returnFiber.mode & StrictLegacyMode || warnAboutStringRefs) &&
// We warn in ReactElement.js if owner and self are equal for string refs
// because these cannot be automatically converted to an arrow function
// using a codemod. Therefore, we don't have to warn about string refs again.
Expand Down
64 changes: 58 additions & 6 deletions packages/react-reconciler/src/ReactFiber.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ import type {OffscreenProps} from './ReactFiberOffscreenComponent';

import invariant from 'shared/invariant';
import {
createRootStrictEffectsByDefault,
enableCache,
enableStrictEffects,
enableProfilerTimer,
enableScopeAPI,
enableCache,
} from 'shared/ReactFeatureFlags';
import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
import {ConcurrentRoot, BlockingRoot} from './ReactRootTags';
Expand Down Expand Up @@ -64,7 +66,8 @@ import {
ConcurrentMode,
DebugTracingMode,
ProfileMode,
StrictMode,
StrictLegacyMode,
StrictEffectsMode,
BlockingMode,
} from './ReactTypeOfMode';
import {
Expand Down Expand Up @@ -418,12 +421,47 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
return workInProgress;
}

export function createHostRootFiber(tag: RootTag): Fiber {
export function createHostRootFiber(
tag: RootTag,
strictModeLevelOverride: null | number,
): Fiber {
let mode;
if (tag === ConcurrentRoot) {
mode = ConcurrentMode | BlockingMode | StrictMode;
mode = ConcurrentMode | BlockingMode;
if (strictModeLevelOverride !== null) {
if (strictModeLevelOverride >= 1) {
mode |= StrictLegacyMode;
}
if (enableStrictEffects) {
if (strictModeLevelOverride >= 2) {
mode |= StrictEffectsMode;
}
}
} else {
if (enableStrictEffects && createRootStrictEffectsByDefault) {
mode |= StrictLegacyMode | StrictEffectsMode;
} else {
mode |= StrictLegacyMode;
}
}
} else if (tag === BlockingRoot) {
mode = BlockingMode | StrictMode;
mode = BlockingMode;
if (strictModeLevelOverride !== null) {
if (strictModeLevelOverride >= 1) {
mode |= StrictLegacyMode;
}
if (enableStrictEffects) {
if (strictModeLevelOverride >= 2) {
mode |= StrictEffectsMode;
}
}
} else {
if (enableStrictEffects && createRootStrictEffectsByDefault) {
mode |= StrictLegacyMode | StrictEffectsMode;
} else {
mode |= StrictLegacyMode;
}
}
} else {
mode = NoMode;
}
Expand Down Expand Up @@ -472,7 +510,21 @@ export function createFiberFromTypeAndProps(
break;
case REACT_STRICT_MODE_TYPE:
fiberTag = Mode;
mode |= StrictMode;

// Legacy strict mode (<StrictMode> without any level prop) defaults to level 1.
const level =
pendingProps.unstable_level == null ? 1 : pendingProps.unstable_level;

// Levels cascade; higher levels inherit all lower level modes.
// It is explicitly not supported to lower a mode with nesting, only to increase it.
if (level >= 1) {
mode |= StrictLegacyMode;
}
if (enableStrictEffects) {
if (level >= 2) {
mode |= StrictEffectsMode;
}
}
break;
case REACT_PROFILER_TYPE:
return createFiberFromProfiler(pendingProps, mode, lanes, key);
Expand Down
64 changes: 58 additions & 6 deletions packages/react-reconciler/src/ReactFiber.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ import type {OffscreenProps} from './ReactFiberOffscreenComponent';

import invariant from 'shared/invariant';
import {
createRootStrictEffectsByDefault,
enableCache,
enableStrictEffects,
enableProfilerTimer,
enableScopeAPI,
enableCache,
} from 'shared/ReactFeatureFlags';
import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
import {ConcurrentRoot, BlockingRoot} from './ReactRootTags';
Expand Down Expand Up @@ -64,7 +66,8 @@ import {
ConcurrentMode,
DebugTracingMode,
ProfileMode,
StrictMode,
StrictLegacyMode,
StrictEffectsMode,
BlockingMode,
} from './ReactTypeOfMode';
import {
Expand Down Expand Up @@ -418,12 +421,47 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
return workInProgress;
}

export function createHostRootFiber(tag: RootTag): Fiber {
export function createHostRootFiber(
tag: RootTag,
strictModeLevelOverride: null | number,
): Fiber {
let mode;
if (tag === ConcurrentRoot) {
mode = ConcurrentMode | BlockingMode | StrictMode;
mode = ConcurrentMode | BlockingMode;
if (strictModeLevelOverride !== null) {
if (strictModeLevelOverride >= 1) {
mode |= StrictLegacyMode;
}
if (enableStrictEffects) {
if (strictModeLevelOverride >= 2) {
mode |= StrictEffectsMode;
}
}
} else {
if (enableStrictEffects && createRootStrictEffectsByDefault) {
mode |= StrictLegacyMode | StrictEffectsMode;
} else {
mode |= StrictLegacyMode;
}
}
} else if (tag === BlockingRoot) {
mode = BlockingMode | StrictMode;
mode = BlockingMode;
if (strictModeLevelOverride !== null) {
if (strictModeLevelOverride >= 1) {
mode |= StrictLegacyMode;
}
if (enableStrictEffects) {
if (strictModeLevelOverride >= 2) {
mode |= StrictEffectsMode;
}
}
} else {
if (enableStrictEffects && createRootStrictEffectsByDefault) {
mode |= StrictLegacyMode | StrictEffectsMode;
} else {
mode |= StrictLegacyMode;
}
}
} else {
mode = NoMode;
}
Expand Down Expand Up @@ -472,7 +510,21 @@ export function createFiberFromTypeAndProps(
break;
case REACT_STRICT_MODE_TYPE:
fiberTag = Mode;
mode |= StrictMode;

// Legacy strict mode (<StrictMode> without any level prop) defaults to level 1.
const level =
pendingProps.unstable_level == null ? 1 : pendingProps.unstable_level;

// Levels cascade; higher levels inherit all lower level modes.
// It is explicitly not supported to lower a mode with nesting, only to increase it.
if (level >= 1) {
mode |= StrictLegacyMode;
}
if (enableStrictEffects) {
if (level >= 2) {
mode |= StrictEffectsMode;
}
}
break;
case REACT_PROFILER_TYPE:
return createFiberFromProfiler(pendingProps, mode, lanes, key);
Expand Down
12 changes: 6 additions & 6 deletions packages/react-reconciler/src/ReactFiberBeginWork.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ import {
ConcurrentMode,
NoMode,
ProfileMode,
StrictMode,
StrictLegacyMode,
BlockingMode,
} from './ReactTypeOfMode';
import {
Expand Down Expand Up @@ -357,7 +357,7 @@ function updateForwardRef(
);
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
workInProgress.mode & StrictLegacyMode
) {
disableLogs();
try {
Expand Down Expand Up @@ -889,7 +889,7 @@ function updateFunctionComponent(
);
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
workInProgress.mode & StrictLegacyMode
) {
disableLogs();
try {
Expand Down Expand Up @@ -1068,7 +1068,7 @@ function finishClassComponent(
nextChildren = instance.render();
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
workInProgress.mode & StrictLegacyMode
) {
disableLogs();
try {
Expand Down Expand Up @@ -1478,7 +1478,7 @@ function mountIndeterminateComponent(
}
}

if (workInProgress.mode & StrictMode) {
if (workInProgress.mode & StrictLegacyMode) {
ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null);
}

Expand Down Expand Up @@ -1615,7 +1615,7 @@ function mountIndeterminateComponent(

if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
workInProgress.mode & StrictLegacyMode
) {
disableLogs();
try {
Expand Down
Loading