Skip to content

Commit

Permalink
Switch to mount dispatcher after use() when needed (#26232)
Browse files Browse the repository at this point in the history
When resuming a suspended render, there may be more Hooks to be called
that weren't seen the previous time through. Make sure to switch to the
mount dispatcher when calling use() if the next Hook call should be
treated as a mount.

Fixes #25964.

DiffTrain build for [a8f971b](a8f971b)
  • Loading branch information
sophiebits committed Feb 24, 2023
1 parent a1ece33 commit 5ae58c5
Show file tree
Hide file tree
Showing 28 changed files with 1,674 additions and 1,626 deletions.
2 changes: 1 addition & 1 deletion compiled/facebook-www/REVISION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
96cdeaf89bfde7551b4ffe4d685da169b780f2f7
a8f971b7a669a9a6321b9f3cea820f68b2e4ac6e
2 changes: 1 addition & 1 deletion compiled/facebook-www/REVISION_TRANSFORMS
Original file line number Diff line number Diff line change
@@ -1 +1 @@
96cdeaf89bfde7551b4ffe4d685da169b780f2f7
a8f971b7a669a9a6321b9f3cea820f68b2e4ac6e
2 changes: 1 addition & 1 deletion compiled/facebook-www/React-dev.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ if (
}
"use strict";

var ReactVersion = "18.3.0-www-classic-96cdeaf89-20230224";
var ReactVersion = "18.3.0-www-classic-a8f971b7a-20230224";

// ATTENTION
// When adding new symbols to this file,
Expand Down
2 changes: 1 addition & 1 deletion compiled/facebook-www/React-dev.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ if (
}
"use strict";

var ReactVersion = "18.3.0-www-modern-96cdeaf89-20230224";
var ReactVersion = "18.3.0-www-modern-a8f971b7a-20230224";

// ATTENTION
// When adding new symbols to this file,
Expand Down
2 changes: 1 addition & 1 deletion compiled/facebook-www/React-prod.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -646,4 +646,4 @@ exports.useSyncExternalStore = function (
);
};
exports.useTransition = useTransition;
exports.version = "18.3.0-www-classic-96cdeaf89-20230224";
exports.version = "18.3.0-www-classic-a8f971b7a-20230224";
2 changes: 1 addition & 1 deletion compiled/facebook-www/React-prod.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -638,4 +638,4 @@ exports.useSyncExternalStore = function (
);
};
exports.useTransition = useTransition;
exports.version = "18.3.0-www-modern-96cdeaf89-20230224";
exports.version = "18.3.0-www-modern-a8f971b7a-20230224";
2 changes: 1 addition & 1 deletion compiled/facebook-www/React-profiling.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ exports.useSyncExternalStore = function (
);
};
exports.useTransition = useTransition;
exports.version = "18.3.0-www-classic-96cdeaf89-20230224";
exports.version = "18.3.0-www-classic-a8f971b7a-20230224";

/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
if (
Expand Down
2 changes: 1 addition & 1 deletion compiled/facebook-www/React-profiling.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ exports.useSyncExternalStore = function (
);
};
exports.useTransition = useTransition;
exports.version = "18.3.0-www-modern-96cdeaf89-20230224";
exports.version = "18.3.0-www-modern-a8f971b7a-20230224";

/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
if (
Expand Down
70 changes: 41 additions & 29 deletions compiled/facebook-www/ReactART-dev.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ function _assertThisInitialized(self) {
return self;
}

var ReactVersion = "18.3.0-www-classic-96cdeaf89-20230224";
var ReactVersion = "18.3.0-www-classic-a8f971b7a-20230224";

var LegacyRoot = 0;
var ConcurrentRoot = 1;
Expand Down Expand Up @@ -7625,7 +7625,6 @@ function replaySuspendedComponentWithHooks(
// only get reset when the component either completes (finishRenderingHooks)
// or unwinds (resetHooksOnUnwind).
{
hookTypesDev = current !== null ? current._debugHookTypes : null;
hookTypesUpdateIndexDev = -1; // Used for hot reloading:

ignorePreviousDependencies =
Expand Down Expand Up @@ -7657,8 +7656,14 @@ function renderWithHooksAgain(workInProgress, Component, props, secondArg) {
var children;

do {
didScheduleRenderPhaseUpdateDuringThisPass = false;
if (didScheduleRenderPhaseUpdateDuringThisPass) {
// It's possible that a use() value depended on a state that was updated in
// this rerender, so we need to watch for different thenables this time.
thenableState = null;
}

thenableIndexCounter = 0;
didScheduleRenderPhaseUpdateDuringThisPass = false;

if (numberOfReRenders >= RE_RENDER_LIMIT) {
throw new Error(
Expand Down Expand Up @@ -7783,8 +7788,7 @@ function updateWorkInProgressHook() {
// This function is used both for updates and for re-renders triggered by a
// render phase update. It assumes there is either a current hook we can
// clone, or a work-in-progress hook from a previous render pass that we can
// use as a base. When we reach the end of the base list, we must switch to
// the dispatcher used for mounts.
// use as a base.
var nextCurrentHook;

if (currentHook === null) {
Expand Down Expand Up @@ -7820,14 +7824,10 @@ function updateWorkInProgressHook() {
if (currentFiber === null) {
// This is the initial render. This branch is reached when the component
// suspends, resumes, then renders an additional hook.
var _newHook = {
memoizedState: null,
baseState: null,
baseQueue: null,
queue: null,
next: null
};
nextCurrentHook = _newHook;
// Should never be reached because we should switch to the mount dispatcher first.
throw new Error(
"Update hook called on initial render. This is likely a bug in React. Please file an issue."
);
} else {
// This is an update. We should always have a current hook.
throw new Error("Rendered more hooks than during the previous render.");
Expand Down Expand Up @@ -7883,7 +7883,24 @@ function use(usable) {
thenableState = createThenableState();
}

return trackUsedThenable(thenableState, thenable, index);
var result = trackUsedThenable(thenableState, thenable, index);

if (
currentlyRenderingFiber$1.alternate === null &&
(workInProgressHook === null
? currentlyRenderingFiber$1.memoizedState === null
: workInProgressHook.next === null)
) {
// Initial render, and either this is the first time the component is
// called, or there were no Hooks called after this use() the previous
// time (perhaps because it threw). Subsequent Hook calls should use the
// mount dispatcher.
{
ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV;
}
}

return result;
} else if (
usable.$$typeof === REACT_CONTEXT_TYPE ||
usable.$$typeof === REACT_SERVER_CONTEXT_TYPE
Expand Down Expand Up @@ -8829,7 +8846,7 @@ function mountEffectImpl(fiberFlags, hookFlags, create, deps) {
function updateEffectImpl(fiberFlags, hookFlags, create, deps) {
var hook = updateWorkInProgressHook();
var nextDeps = deps === undefined ? null : deps;
var destroy = undefined;
var destroy = undefined; // currentHook is null when rerendering after a render phase state update.

if (currentHook !== null) {
var prevEffect = currentHook.memoizedState;
Expand Down Expand Up @@ -9047,13 +9064,11 @@ function updateCallback(callback, deps) {
var nextDeps = deps === undefined ? null : deps;
var prevState = hook.memoizedState;

if (prevState !== null) {
if (nextDeps !== null) {
var prevDeps = prevState[1];
if (nextDeps !== null) {
var prevDeps = prevState[1];

if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}

Expand All @@ -9077,16 +9092,13 @@ function mountMemo(nextCreate, deps) {
function updateMemo(nextCreate, deps) {
var hook = updateWorkInProgressHook();
var nextDeps = deps === undefined ? null : deps;
var prevState = hook.memoizedState;
var prevState = hook.memoizedState; // Assume these are defined. If they're not, areHookInputsEqual will warn.

if (prevState !== null) {
// Assume these are defined. If they're not, areHookInputsEqual will warn.
if (nextDeps !== null) {
var prevDeps = prevState[1];
if (nextDeps !== null) {
var prevDeps = prevState[1];

if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}

Expand Down
70 changes: 41 additions & 29 deletions compiled/facebook-www/ReactART-dev.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ function _assertThisInitialized(self) {
return self;
}

var ReactVersion = "18.3.0-www-modern-96cdeaf89-20230224";
var ReactVersion = "18.3.0-www-modern-a8f971b7a-20230224";

var LegacyRoot = 0;
var ConcurrentRoot = 1;
Expand Down Expand Up @@ -7381,7 +7381,6 @@ function replaySuspendedComponentWithHooks(
// only get reset when the component either completes (finishRenderingHooks)
// or unwinds (resetHooksOnUnwind).
{
hookTypesDev = current !== null ? current._debugHookTypes : null;
hookTypesUpdateIndexDev = -1; // Used for hot reloading:

ignorePreviousDependencies =
Expand Down Expand Up @@ -7413,8 +7412,14 @@ function renderWithHooksAgain(workInProgress, Component, props, secondArg) {
var children;

do {
didScheduleRenderPhaseUpdateDuringThisPass = false;
if (didScheduleRenderPhaseUpdateDuringThisPass) {
// It's possible that a use() value depended on a state that was updated in
// this rerender, so we need to watch for different thenables this time.
thenableState = null;
}

thenableIndexCounter = 0;
didScheduleRenderPhaseUpdateDuringThisPass = false;

if (numberOfReRenders >= RE_RENDER_LIMIT) {
throw new Error(
Expand Down Expand Up @@ -7539,8 +7544,7 @@ function updateWorkInProgressHook() {
// This function is used both for updates and for re-renders triggered by a
// render phase update. It assumes there is either a current hook we can
// clone, or a work-in-progress hook from a previous render pass that we can
// use as a base. When we reach the end of the base list, we must switch to
// the dispatcher used for mounts.
// use as a base.
var nextCurrentHook;

if (currentHook === null) {
Expand Down Expand Up @@ -7576,14 +7580,10 @@ function updateWorkInProgressHook() {
if (currentFiber === null) {
// This is the initial render. This branch is reached when the component
// suspends, resumes, then renders an additional hook.
var _newHook = {
memoizedState: null,
baseState: null,
baseQueue: null,
queue: null,
next: null
};
nextCurrentHook = _newHook;
// Should never be reached because we should switch to the mount dispatcher first.
throw new Error(
"Update hook called on initial render. This is likely a bug in React. Please file an issue."
);
} else {
// This is an update. We should always have a current hook.
throw new Error("Rendered more hooks than during the previous render.");
Expand Down Expand Up @@ -7639,7 +7639,24 @@ function use(usable) {
thenableState = createThenableState();
}

return trackUsedThenable(thenableState, thenable, index);
var result = trackUsedThenable(thenableState, thenable, index);

if (
currentlyRenderingFiber$1.alternate === null &&
(workInProgressHook === null
? currentlyRenderingFiber$1.memoizedState === null
: workInProgressHook.next === null)
) {
// Initial render, and either this is the first time the component is
// called, or there were no Hooks called after this use() the previous
// time (perhaps because it threw). Subsequent Hook calls should use the
// mount dispatcher.
{
ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV;
}
}

return result;
} else if (
usable.$$typeof === REACT_CONTEXT_TYPE ||
usable.$$typeof === REACT_SERVER_CONTEXT_TYPE
Expand Down Expand Up @@ -8585,7 +8602,7 @@ function mountEffectImpl(fiberFlags, hookFlags, create, deps) {
function updateEffectImpl(fiberFlags, hookFlags, create, deps) {
var hook = updateWorkInProgressHook();
var nextDeps = deps === undefined ? null : deps;
var destroy = undefined;
var destroy = undefined; // currentHook is null when rerendering after a render phase state update.

if (currentHook !== null) {
var prevEffect = currentHook.memoizedState;
Expand Down Expand Up @@ -8803,13 +8820,11 @@ function updateCallback(callback, deps) {
var nextDeps = deps === undefined ? null : deps;
var prevState = hook.memoizedState;

if (prevState !== null) {
if (nextDeps !== null) {
var prevDeps = prevState[1];
if (nextDeps !== null) {
var prevDeps = prevState[1];

if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}

Expand All @@ -8833,16 +8848,13 @@ function mountMemo(nextCreate, deps) {
function updateMemo(nextCreate, deps) {
var hook = updateWorkInProgressHook();
var nextDeps = deps === undefined ? null : deps;
var prevState = hook.memoizedState;
var prevState = hook.memoizedState; // Assume these are defined. If they're not, areHookInputsEqual will warn.

if (prevState !== null) {
// Assume these are defined. If they're not, areHookInputsEqual will warn.
if (nextDeps !== null) {
var prevDeps = prevState[1];
if (nextDeps !== null) {
var prevDeps = prevState[1];

if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}

Expand Down
Loading

0 comments on commit 5ae58c5

Please sign in to comment.