Skip to content

Commit

Permalink
Add StrictMode levels 1 & 2
Browse files Browse the repository at this point in the history
The exported React.StrictMode tag remains the same and opts legacy subtrees into strict mode level one (mode = StrictModeL1). This mode enables DEV-only double rendering, double component lifecycles, string ref warnings, legacy context warnings, etc. The primary purpose of this mode is to help detected render phase side effects. No new behavior. Roots created with experimental  and  APIs will also (for now) continue to default to strict mode level 1.

In a subsequent commit I will add support for a 'level' attribute on the React.StrictMode tag (as well as a new option supported by ). This will be the way to opt into strict mode level 2 (mode = StrictModeL2). This mode will enable DEV-only double invoking of effects on initial mount. This will simulate future Offscreen API semantics for trees being mounted, then hidden, and then shown again. The primary purpose of this mode is to enable applications to prepare for compatibility with the new Offscreen API (more information to follow shortly).

For now, this commit changes no public facing behavior.
  • Loading branch information
Brian Vaughn committed Feb 18, 2021
1 parent 8af27ae commit e12cf07
Show file tree
Hide file tree
Showing 22 changed files with 153 additions and 121 deletions.
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 {StrictModeL1} 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 & StrictModeL1 || 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 {StrictModeL1} 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 & StrictModeL1 || 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
21 changes: 16 additions & 5 deletions packages/react-reconciler/src/ReactFiber.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ import type {OffscreenProps} from './ReactFiberOffscreenComponent';

import invariant from 'shared/invariant';
import {
enableCache,
enableDoubleInvokingEffects,
enableProfilerTimer,
enableScopeAPI,
enableCache,
} from 'shared/ReactFeatureFlags';
import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
import {ConcurrentRoot, BlockingRoot} from './ReactRootTags';
Expand Down Expand Up @@ -64,7 +65,8 @@ import {
ConcurrentMode,
DebugTracingMode,
ProfileMode,
StrictMode,
StrictModeL1,
StrictModeL2,
BlockingMode,
} from './ReactTypeOfMode';
import {
Expand Down Expand Up @@ -421,9 +423,17 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
export function createHostRootFiber(tag: RootTag): Fiber {
let mode;
if (tag === ConcurrentRoot) {
mode = ConcurrentMode | BlockingMode | StrictMode;
if (enableDoubleInvokingEffects) {
mode = ConcurrentMode | BlockingMode | StrictModeL1 | StrictModeL2;
} else {
mode = ConcurrentMode | BlockingMode | StrictModeL1;
}
} else if (tag === BlockingRoot) {
mode = BlockingMode | StrictMode;
if (enableDoubleInvokingEffects) {
mode = BlockingMode | StrictModeL1 | StrictModeL2;
} else {
mode = BlockingMode | StrictModeL1;
}
} else {
mode = NoMode;
}
Expand Down Expand Up @@ -472,7 +482,8 @@ export function createFiberFromTypeAndProps(
break;
case REACT_STRICT_MODE_TYPE:
fiberTag = Mode;
mode |= StrictMode;
// TODO (StrictModeL2) Add support for new strict mode "level" attribute
mode |= StrictModeL1;
break;
case REACT_PROFILER_TYPE:
return createFiberFromProfiler(pendingProps, mode, lanes, key);
Expand Down
21 changes: 16 additions & 5 deletions packages/react-reconciler/src/ReactFiber.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ import type {OffscreenProps} from './ReactFiberOffscreenComponent';

import invariant from 'shared/invariant';
import {
enableCache,
enableDoubleInvokingEffects,
enableProfilerTimer,
enableScopeAPI,
enableCache,
} from 'shared/ReactFeatureFlags';
import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
import {ConcurrentRoot, BlockingRoot} from './ReactRootTags';
Expand Down Expand Up @@ -64,7 +65,8 @@ import {
ConcurrentMode,
DebugTracingMode,
ProfileMode,
StrictMode,
StrictModeL1,
StrictModeL2,
BlockingMode,
} from './ReactTypeOfMode';
import {
Expand Down Expand Up @@ -421,9 +423,17 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
export function createHostRootFiber(tag: RootTag): Fiber {
let mode;
if (tag === ConcurrentRoot) {
mode = ConcurrentMode | BlockingMode | StrictMode;
if (enableDoubleInvokingEffects) {
mode = ConcurrentMode | BlockingMode | StrictModeL1 | StrictModeL2;
} else {
mode = ConcurrentMode | BlockingMode | StrictModeL1;
}
} else if (tag === BlockingRoot) {
mode = BlockingMode | StrictMode;
if (enableDoubleInvokingEffects) {
mode = BlockingMode | StrictModeL1 | StrictModeL2;
} else {
mode = BlockingMode | StrictModeL1;
}
} else {
mode = NoMode;
}
Expand Down Expand Up @@ -472,7 +482,8 @@ export function createFiberFromTypeAndProps(
break;
case REACT_STRICT_MODE_TYPE:
fiberTag = Mode;
mode |= StrictMode;
// TODO (StrictModeL2) Add support for new strict mode "level" attribute
mode |= StrictModeL1;
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,
StrictModeL1,
BlockingMode,
} from './ReactTypeOfMode';
import {
Expand Down Expand Up @@ -357,7 +357,7 @@ function updateForwardRef(
);
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
workInProgress.mode & StrictModeL1
) {
disableLogs();
try {
Expand Down Expand Up @@ -889,7 +889,7 @@ function updateFunctionComponent(
);
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
workInProgress.mode & StrictModeL1
) {
disableLogs();
try {
Expand Down Expand Up @@ -1068,7 +1068,7 @@ function finishClassComponent(
nextChildren = instance.render();
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
workInProgress.mode & StrictModeL1
) {
disableLogs();
try {
Expand Down Expand Up @@ -1478,7 +1478,7 @@ function mountIndeterminateComponent(
}
}

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

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

if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
workInProgress.mode & StrictModeL1
) {
disableLogs();
try {
Expand Down
12 changes: 6 additions & 6 deletions packages/react-reconciler/src/ReactFiberBeginWork.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ import {
ConcurrentMode,
NoMode,
ProfileMode,
StrictMode,
StrictModeL1,
BlockingMode,
} from './ReactTypeOfMode';
import {
Expand Down Expand Up @@ -357,7 +357,7 @@ function updateForwardRef(
);
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
workInProgress.mode & StrictModeL1
) {
disableLogs();
try {
Expand Down Expand Up @@ -889,7 +889,7 @@ function updateFunctionComponent(
);
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
workInProgress.mode & StrictModeL1
) {
disableLogs();
try {
Expand Down Expand Up @@ -1068,7 +1068,7 @@ function finishClassComponent(
nextChildren = instance.render();
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
workInProgress.mode & StrictModeL1
) {
disableLogs();
try {
Expand Down Expand Up @@ -1478,7 +1478,7 @@ function mountIndeterminateComponent(
}
}

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

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

if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
workInProgress.mode & StrictModeL1
) {
disableLogs();
try {
Expand Down
21 changes: 10 additions & 11 deletions packages/react-reconciler/src/ReactFiberClassComponent.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,10 @@ import {REACT_CONTEXT_TYPE, REACT_PROVIDER_TYPE} from 'shared/ReactSymbols';

import {resolveDefaultProps} from './ReactFiberLazyComponent.new';
import {
BlockingMode,
ConcurrentMode,
DebugTracingMode,
NoMode,
StrictMode,
StrictModeL1,
StrictModeL2,
} from './ReactTypeOfMode';

import {
Expand Down Expand Up @@ -165,7 +164,7 @@ export function applyDerivedStateFromProps(
if (__DEV__) {
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
workInProgress.mode & StrictModeL1
) {
disableLogs();
try {
Expand Down Expand Up @@ -318,7 +317,7 @@ function checkShouldComponentUpdate(
if (__DEV__) {
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
workInProgress.mode & StrictModeL1
) {
disableLogs();
try {
Expand Down Expand Up @@ -655,7 +654,7 @@ function constructClassInstance(
if (__DEV__) {
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
workInProgress.mode & StrictModeL1
) {
disableLogs();
try {
Expand Down Expand Up @@ -862,7 +861,7 @@ function mountClassInstance(
}
}

if (workInProgress.mode & StrictMode) {
if (workInProgress.mode & StrictModeL1) {
ReactStrictModeWarnings.recordLegacyContextWarning(
workInProgress,
instance,
Expand Down Expand Up @@ -910,7 +909,7 @@ function mountClassInstance(
if (
__DEV__ &&
enableDoubleInvokingEffects &&
(workInProgress.mode & (BlockingMode | ConcurrentMode)) !== NoMode
(workInProgress.mode & StrictModeL2) !== NoMode
) {
// Never double-invoke effects for legacy roots.
workInProgress.flags |= MountLayoutDev | Update;
Expand Down Expand Up @@ -989,7 +988,7 @@ function resumeMountClassInstance(
if (
__DEV__ &&
enableDoubleInvokingEffects &&
(workInProgress.mode & (BlockingMode | ConcurrentMode)) !== NoMode
(workInProgress.mode & StrictModeL2) !== NoMode
) {
// Never double-invoke effects for legacy roots.
workInProgress.flags |= MountLayoutDev | Update;
Expand Down Expand Up @@ -1041,7 +1040,7 @@ function resumeMountClassInstance(
if (
__DEV__ &&
enableDoubleInvokingEffects &&
(workInProgress.mode & (BlockingMode | ConcurrentMode)) !== NoMode
(workInProgress.mode & StrictModeL2) !== NoMode
) {
// Never double-invoke effects for legacy roots.
workInProgress.flags |= MountLayoutDev | Update;
Expand All @@ -1056,7 +1055,7 @@ function resumeMountClassInstance(
if (
__DEV__ &&
enableDoubleInvokingEffects &&
(workInProgress.mode & (BlockingMode | ConcurrentMode)) !== NoMode
(workInProgress.mode & StrictModeL2) !== NoMode
) {
// Never double-invoke effects for legacy roots.
workInProgress.flags |= MountLayoutDev | Update;
Expand Down
Loading

0 comments on commit e12cf07

Please sign in to comment.