mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Revert "Revert "Double-render function components with Hooks in DEV in StrictMode" (#14652)" (#14654)
This reverts commit 3fbebb2a0b.
This commit is contained in:
@@ -250,6 +250,23 @@ function updateForwardRef(
|
||||
ref,
|
||||
renderExpirationTime,
|
||||
);
|
||||
if (
|
||||
debugRenderPhaseSideEffects ||
|
||||
(debugRenderPhaseSideEffectsForStrictMode &&
|
||||
workInProgress.mode & StrictMode)
|
||||
) {
|
||||
// Only double-render components with Hooks
|
||||
if (workInProgress.memoizedState !== null) {
|
||||
renderWithHooks(
|
||||
current,
|
||||
workInProgress,
|
||||
render,
|
||||
nextProps,
|
||||
ref,
|
||||
renderExpirationTime,
|
||||
);
|
||||
}
|
||||
}
|
||||
setCurrentPhase(null);
|
||||
} else {
|
||||
nextChildren = renderWithHooks(
|
||||
@@ -543,6 +560,23 @@ function updateFunctionComponent(
|
||||
context,
|
||||
renderExpirationTime,
|
||||
);
|
||||
if (
|
||||
debugRenderPhaseSideEffects ||
|
||||
(debugRenderPhaseSideEffectsForStrictMode &&
|
||||
workInProgress.mode & StrictMode)
|
||||
) {
|
||||
// Only double-render components with Hooks
|
||||
if (workInProgress.memoizedState !== null) {
|
||||
renderWithHooks(
|
||||
current,
|
||||
workInProgress,
|
||||
Component,
|
||||
nextProps,
|
||||
context,
|
||||
renderExpirationTime,
|
||||
);
|
||||
}
|
||||
}
|
||||
setCurrentPhase(null);
|
||||
} else {
|
||||
nextChildren = renderWithHooks(
|
||||
@@ -1210,6 +1244,25 @@ function mountIndeterminateComponent(
|
||||
} else {
|
||||
// Proceed under the assumption that this is a function component
|
||||
workInProgress.tag = FunctionComponent;
|
||||
if (__DEV__) {
|
||||
if (
|
||||
debugRenderPhaseSideEffects ||
|
||||
(debugRenderPhaseSideEffectsForStrictMode &&
|
||||
workInProgress.mode & StrictMode)
|
||||
) {
|
||||
// Only double-render components with Hooks
|
||||
if (workInProgress.memoizedState !== null) {
|
||||
renderWithHooks(
|
||||
null,
|
||||
workInProgress,
|
||||
Component,
|
||||
props,
|
||||
context,
|
||||
renderExpirationTime,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
reconcileChildren(null, workInProgress, value, renderExpirationTime);
|
||||
if (__DEV__) {
|
||||
validateFunctionComponentInDev(workInProgress, Component);
|
||||
|
||||
@@ -841,6 +841,226 @@ describe('ReactHooks', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('double-invokes components with Hooks in Strict Mode', () => {
|
||||
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = true;
|
||||
|
||||
const {useState, StrictMode} = React;
|
||||
let renderCount = 0;
|
||||
|
||||
function NoHooks() {
|
||||
renderCount++;
|
||||
return <div />;
|
||||
}
|
||||
|
||||
function HasHooks() {
|
||||
useState(0);
|
||||
renderCount++;
|
||||
return <div />;
|
||||
}
|
||||
|
||||
const FwdRef = React.forwardRef((props, ref) => {
|
||||
renderCount++;
|
||||
return <div />;
|
||||
});
|
||||
|
||||
const FwdRefHasHooks = React.forwardRef((props, ref) => {
|
||||
useState(0);
|
||||
renderCount++;
|
||||
return <div />;
|
||||
});
|
||||
|
||||
const Memo = React.memo(props => {
|
||||
renderCount++;
|
||||
return <div />;
|
||||
});
|
||||
|
||||
const MemoHasHooks = React.memo(props => {
|
||||
useState(0);
|
||||
renderCount++;
|
||||
return <div />;
|
||||
});
|
||||
|
||||
function Factory() {
|
||||
return {
|
||||
state: {},
|
||||
render() {
|
||||
renderCount++;
|
||||
return <div />;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
let renderer = ReactTestRenderer.create(null);
|
||||
|
||||
renderCount = 0;
|
||||
renderer.update(<NoHooks />);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(<NoHooks />);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(
|
||||
<StrictMode>
|
||||
<NoHooks />
|
||||
</StrictMode>,
|
||||
);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(
|
||||
<StrictMode>
|
||||
<NoHooks />
|
||||
</StrictMode>,
|
||||
);
|
||||
expect(renderCount).toBe(1);
|
||||
|
||||
renderCount = 0;
|
||||
renderer.update(<FwdRef />);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(<FwdRef />);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(
|
||||
<StrictMode>
|
||||
<FwdRef />
|
||||
</StrictMode>,
|
||||
);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(
|
||||
<StrictMode>
|
||||
<FwdRef />
|
||||
</StrictMode>,
|
||||
);
|
||||
expect(renderCount).toBe(1);
|
||||
|
||||
renderCount = 0;
|
||||
renderer.update(<Memo arg={1} />);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(<Memo arg={2} />);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(
|
||||
<StrictMode>
|
||||
<Memo arg={1} />
|
||||
</StrictMode>,
|
||||
);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(
|
||||
<StrictMode>
|
||||
<Memo arg={2} />
|
||||
</StrictMode>,
|
||||
);
|
||||
expect(renderCount).toBe(1);
|
||||
|
||||
renderCount = 0;
|
||||
renderer.update(<Factory />);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(<Factory />);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(
|
||||
<StrictMode>
|
||||
<Factory />
|
||||
</StrictMode>,
|
||||
);
|
||||
expect(renderCount).toBe(__DEV__ ? 2 : 1); // Treated like a class
|
||||
renderCount = 0;
|
||||
renderer.update(
|
||||
<StrictMode>
|
||||
<Factory />
|
||||
</StrictMode>,
|
||||
);
|
||||
expect(renderCount).toBe(__DEV__ ? 2 : 1); // Treated like a class
|
||||
|
||||
renderCount = 0;
|
||||
renderer.update(<HasHooks />);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(<HasHooks />);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(
|
||||
<StrictMode>
|
||||
<HasHooks />
|
||||
</StrictMode>,
|
||||
);
|
||||
expect(renderCount).toBe(__DEV__ ? 2 : 1); // Has Hooks
|
||||
renderCount = 0;
|
||||
renderer.update(
|
||||
<StrictMode>
|
||||
<HasHooks />
|
||||
</StrictMode>,
|
||||
);
|
||||
expect(renderCount).toBe(__DEV__ ? 2 : 1); // Has Hooks
|
||||
|
||||
renderCount = 0;
|
||||
renderer.update(<FwdRefHasHooks />);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(<FwdRefHasHooks />);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(
|
||||
<StrictMode>
|
||||
<FwdRefHasHooks />
|
||||
</StrictMode>,
|
||||
);
|
||||
expect(renderCount).toBe(__DEV__ ? 2 : 1); // Has Hooks
|
||||
renderCount = 0;
|
||||
renderer.update(
|
||||
<StrictMode>
|
||||
<FwdRefHasHooks />
|
||||
</StrictMode>,
|
||||
);
|
||||
expect(renderCount).toBe(__DEV__ ? 2 : 1); // Has Hooks
|
||||
|
||||
renderCount = 0;
|
||||
renderer.update(<MemoHasHooks arg={1} />);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(<MemoHasHooks arg={2} />);
|
||||
expect(renderCount).toBe(1);
|
||||
renderCount = 0;
|
||||
renderer.update(
|
||||
<StrictMode>
|
||||
<MemoHasHooks arg={1} />
|
||||
</StrictMode>,
|
||||
);
|
||||
expect(renderCount).toBe(__DEV__ ? 2 : 1); // Has Hooks
|
||||
renderCount = 0;
|
||||
renderer.update(
|
||||
<StrictMode>
|
||||
<MemoHasHooks arg={2} />
|
||||
</StrictMode>,
|
||||
);
|
||||
expect(renderCount).toBe(__DEV__ ? 2 : 1); // Has Hooks
|
||||
});
|
||||
|
||||
it('double-invokes useMemo in DEV StrictMode despite []', () => {
|
||||
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = true;
|
||||
const {useMemo, StrictMode} = React;
|
||||
|
||||
let useMemoCount = 0;
|
||||
function BadUseMemo() {
|
||||
useMemo(() => {
|
||||
useMemoCount++;
|
||||
}, []);
|
||||
return <div />;
|
||||
}
|
||||
|
||||
useMemoCount = 0;
|
||||
ReactTestRenderer.create(
|
||||
<StrictMode>
|
||||
<BadUseMemo />
|
||||
</StrictMode>,
|
||||
);
|
||||
expect(useMemoCount).toBe(__DEV__ ? 2 : 1); // Has Hooks
|
||||
});
|
||||
|
||||
it('warns on using differently ordered hooks on subsequent renders', () => {
|
||||
const {useState, useReducer} = React;
|
||||
function useCustomHook() {
|
||||
|
||||
Reference in New Issue
Block a user