Skip to content

Commit 215cf14

Browse files
committed
Track separate SuspendedOnAction flag by rethrowing a separate SuspenseActionException sentinel (#31554)
This lets us track separately if something was suspended on an Action using useActionState rather than suspended on Data. This approach feels quite bloated and it seems like we'd eventually might want to read more information about the Promise that suspended and the context it suspended in. As a more general reason for suspending. The way useActionState works in combination with the prewarming is quite unfortunate because 1) it renders blocking to update the isPending flag whether you use it or not 2) it prewarms and suspends the useActionState 3) then it does another third render to get back into the useActionState position again. DiffTrain build for [92c0f5f](92c0f5f)
1 parent 6aab938 commit 215cf14

34 files changed

+1154
-658
lines changed

compiled/facebook-www/React-dev.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1819,7 +1819,7 @@ __DEV__ &&
18191819
exports.useTransition = function () {
18201820
return resolveDispatcher().useTransition();
18211821
};
1822-
exports.version = "19.0.0-www-classic-053b3cb0-20241115";
1822+
exports.version = "19.0.0-www-classic-92c0f5f8-20241115";
18231823
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
18241824
"function" ===
18251825
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-dev.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1819,7 +1819,7 @@ __DEV__ &&
18191819
exports.useTransition = function () {
18201820
return resolveDispatcher().useTransition();
18211821
};
1822-
exports.version = "19.0.0-www-modern-053b3cb0-20241115";
1822+
exports.version = "19.0.0-www-modern-92c0f5f8-20241115";
18231823
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
18241824
"function" ===
18251825
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-prod.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,4 +619,4 @@ exports.useSyncExternalStore = function (
619619
exports.useTransition = function () {
620620
return ReactSharedInternals.H.useTransition();
621621
};
622-
exports.version = "19.0.0-www-classic-053b3cb0-20241115";
622+
exports.version = "19.0.0-www-classic-92c0f5f8-20241115";

compiled/facebook-www/React-prod.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,4 +619,4 @@ exports.useSyncExternalStore = function (
619619
exports.useTransition = function () {
620620
return ReactSharedInternals.H.useTransition();
621621
};
622-
exports.version = "19.0.0-www-modern-053b3cb0-20241115";
622+
exports.version = "19.0.0-www-modern-92c0f5f8-20241115";

compiled/facebook-www/React-profiling.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ exports.useSyncExternalStore = function (
623623
exports.useTransition = function () {
624624
return ReactSharedInternals.H.useTransition();
625625
};
626-
exports.version = "19.0.0-www-classic-053b3cb0-20241115";
626+
exports.version = "19.0.0-www-classic-92c0f5f8-20241115";
627627
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
628628
"function" ===
629629
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-profiling.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ exports.useSyncExternalStore = function (
623623
exports.useTransition = function () {
624624
return ReactSharedInternals.H.useTransition();
625625
};
626-
exports.version = "19.0.0-www-modern-053b3cb0-20241115";
626+
exports.version = "19.0.0-www-modern-92c0f5f8-20241115";
627627
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
628628
"function" ===
629629
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/ReactART-dev.classic.js

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2239,7 +2239,8 @@ __DEV__ &&
22392239
if (
22402240
0 === suspendedLanes ||
22412241
(root === currentTime &&
2242-
workInProgressSuspendedReason === SuspendedOnData) ||
2242+
(workInProgressSuspendedReason === SuspendedOnData ||
2243+
workInProgressSuspendedReason === SuspendedOnAction)) ||
22432244
null !== root.cancelPendingCommit
22442245
)
22452246
return (
@@ -2805,7 +2806,10 @@ __DEV__ &&
28052806
return thenable;
28062807
}
28072808
function checkIfUseWrappedInAsyncCatch(rejectedReason) {
2808-
if (rejectedReason === SuspenseException)
2809+
if (
2810+
rejectedReason === SuspenseException ||
2811+
rejectedReason === SuspenseActionException
2812+
)
28092813
throw Error(
28102814
"Hooks are not supported inside an async component. This error is often caused by accidentally adding `'use client'` to a module that was originally written for the server."
28112815
);
@@ -3827,7 +3831,7 @@ __DEV__ &&
38273831
thenableState$1 = null;
38283832
return firstChildFiber;
38293833
} catch (x) {
3830-
if (x === SuspenseException) throw x;
3834+
if (x === SuspenseException || x === SuspenseActionException) throw x;
38313835
var fiber = createFiber(29, x, null, returnFiber.mode);
38323836
fiber.lanes = lanes;
38333837
fiber.return = returnFiber;
@@ -4918,24 +4922,30 @@ __DEV__ &&
49184922
actionStateReducer
49194923
)[0];
49204924
stateHook = updateReducer(basicStateReducer)[0];
4921-
currentStateHook =
4925+
if (
49224926
"object" === typeof currentStateHook &&
49234927
null !== currentStateHook &&
49244928
"function" === typeof currentStateHook.then
4925-
? useThenable(currentStateHook)
4926-
: currentStateHook;
4927-
var actionQueueHook = updateWorkInProgressHook(),
4928-
actionQueue = actionQueueHook.queue,
4929+
)
4930+
try {
4931+
var state = useThenable(currentStateHook);
4932+
} catch (x) {
4933+
if (x === SuspenseException) throw SuspenseActionException;
4934+
throw x;
4935+
}
4936+
else state = currentStateHook;
4937+
currentStateHook = updateWorkInProgressHook();
4938+
var actionQueue = currentStateHook.queue,
49294939
dispatch = actionQueue.dispatch;
4930-
action !== actionQueueHook.memoizedState &&
4940+
action !== currentStateHook.memoizedState &&
49314941
((currentlyRenderingFiber$1.flags |= 2048),
49324942
pushEffect(
49334943
HasEffect | Passive,
49344944
actionStateActionEffect.bind(null, actionQueue, action),
49354945
{ destroy: void 0 },
49364946
null
49374947
));
4938-
return [currentStateHook, dispatch, stateHook];
4948+
return [state, dispatch, stateHook];
49394949
}
49404950
function actionStateActionEffect(actionQueue, action) {
49414951
actionQueue.action = action;
@@ -12174,7 +12184,8 @@ __DEV__ &&
1217412184
isFlushingPassiveEffects && (didScheduleUpdateDuringPassiveEffects = !0);
1217512185
if (
1217612186
(root === workInProgressRoot &&
12177-
workInProgressSuspendedReason === SuspendedOnData) ||
12187+
(workInProgressSuspendedReason === SuspendedOnData ||
12188+
workInProgressSuspendedReason === SuspendedOnAction)) ||
1217812189
null !== root.cancelPendingCommit
1217912190
)
1218012191
prepareFreshStack(root, 0),
@@ -12639,7 +12650,10 @@ __DEV__ &&
1263912650
ReactSharedInternals.getCurrentStack = null;
1264012651
isRendering = !1;
1264112652
current = null;
12642-
if (thrownValue === SuspenseException) {
12653+
if (
12654+
thrownValue === SuspenseException ||
12655+
thrownValue === SuspenseActionException
12656+
) {
1264312657
thrownValue = getSuspendedThenable();
1264412658
var JSCompiler_temp;
1264512659
if ((JSCompiler_temp = !enableSiblingPrerendering))
@@ -12661,7 +12675,9 @@ __DEV__ &&
1266112675
JSCompiler_temp &&
1266212676
0 === (workInProgressRootSkippedLanes & 134217727) &&
1266312677
0 === (workInProgressRootInterleavedUpdatedLanes & 134217727)
12664-
? SuspendedOnData
12678+
? thrownValue === SuspenseActionException
12679+
? SuspendedOnAction
12680+
: SuspendedOnData
1266512681
: SuspendedOnImmediate;
1266612682
} else
1266712683
thrownValue === SuspenseyCommitException
@@ -12701,6 +12717,7 @@ __DEV__ &&
1270112717
);
1270212718
break;
1270312719
case SuspendedOnData:
12720+
case SuspendedOnAction:
1270412721
case SuspendedOnImmediate:
1270512722
case SuspendedOnDeprecatedThrowPromise:
1270612723
case SuspendedAndReadyToContinue:
@@ -12780,6 +12797,7 @@ __DEV__ &&
1278012797
break a;
1278112798
case SuspendedOnImmediate:
1278212799
case SuspendedOnData:
12800+
case SuspendedOnAction:
1278312801
case SuspendedOnDeprecatedThrowPromise:
1278412802
null === suspenseHandlerStackCursor.current && (lanes = !0);
1278512803
var reason = workInProgressSuspendedReason;
@@ -12873,15 +12891,17 @@ __DEV__ &&
1287312891
);
1287412892
break;
1287512893
case SuspendedOnData:
12894+
case SuspendedOnAction:
1287612895
if (isThenableResolved(memoizedUpdaters)) {
1287712896
workInProgressSuspendedReason = NotSuspended;
1287812897
workInProgressThrownValue = null;
1287912898
replaySuspendedUnitOfWork(lanes);
1288012899
break;
1288112900
}
1288212901
lanes = function () {
12883-
workInProgressSuspendedReason === SuspendedOnData &&
12884-
workInProgressRoot === root &&
12902+
(workInProgressSuspendedReason !== SuspendedOnData &&
12903+
workInProgressSuspendedReason !== SuspendedOnAction) ||
12904+
workInProgressRoot !== root ||
1288512905
(workInProgressSuspendedReason =
1288612906
SuspendedAndReadyToContinue);
1288712907
ensureRootIsScheduled(root);
@@ -13140,6 +13160,7 @@ __DEV__ &&
1314013160
if (
1314113161
((workInProgressRootDidSkipSuspendedSiblings = root = !0),
1314213162
suspendedReason === SuspendedOnData ||
13163+
suspendedReason === SuspendedOnAction ||
1314313164
suspendedReason === SuspendedOnImmediate ||
1314413165
suspendedReason === SuspendedOnDeprecatedThrowPromise)
1314513166
)
@@ -14883,11 +14904,14 @@ __DEV__ &&
1488314904
pendingLegacyContextWarning = new Map();
1488414905
};
1488514906
var SuspenseException = Error(
14886-
"Suspense Exception: This is not a real error! It's an implementation detail of `use` to interrupt the current render. You must either rethrow it immediately, or move the `use` call outside of the `try/catch` block. Capturing without rethrowing will lead to unexpected behavior.\n\nTo handle async errors, wrap your component in an error boundary, or call the promise's `.catch` method and pass the result to `use`"
14907+
"Suspense Exception: This is not a real error! It's an implementation detail of `use` to interrupt the current render. You must either rethrow it immediately, or move the `use` call outside of the `try/catch` block. Capturing without rethrowing will lead to unexpected behavior.\n\nTo handle async errors, wrap your component in an error boundary, or call the promise's `.catch` method and pass the result to `use`."
1488714908
),
1488814909
SuspenseyCommitException = Error(
1488914910
"Suspense Exception: This is not a real error, and should not leak into userspace. If you're seeing this, it's likely a bug in React."
1489014911
),
14912+
SuspenseActionException = Error(
14913+
"Suspense Exception: This is not a real error! It's an implementation detail of `useActionState` to interrupt the current render. You must either rethrow it immediately, or move the `useActionState` call outside of the `try/catch` block. Capturing without rethrowing will lead to unexpected behavior.\n\nTo handle async errors, wrap your component in an error boundary."
14914+
),
1489114915
noopSuspenseyCommitThenable = {
1489214916
then: function () {
1489314917
error$jscomp$0(
@@ -16454,6 +16478,7 @@ __DEV__ &&
1645416478
SuspendedOnDeprecatedThrowPromise = 6,
1645516479
SuspendedAndReadyToContinue = 7,
1645616480
SuspendedOnHydration = 8,
16481+
SuspendedOnAction = 9,
1645716482
workInProgressSuspendedReason = NotSuspended,
1645816483
workInProgressThrownValue = null,
1645916484
workInProgressRootDidSkipSuspendedSiblings = !1,
@@ -16717,11 +16742,11 @@ __DEV__ &&
1671716742
(function () {
1671816743
var internals = {
1671916744
bundleType: 1,
16720-
version: "19.0.0-www-classic-053b3cb0-20241115",
16745+
version: "19.0.0-www-classic-92c0f5f8-20241115",
1672116746
rendererPackageName: "react-art",
1672216747
currentDispatcherRef: ReactSharedInternals,
1672316748
findFiberByHostInstance: getInstanceFromNode,
16724-
reconcilerVersion: "19.0.0-www-classic-053b3cb0-20241115"
16749+
reconcilerVersion: "19.0.0-www-classic-92c0f5f8-20241115"
1672516750
};
1672616751
internals.overrideHookState = overrideHookState;
1672716752
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -16755,7 +16780,7 @@ __DEV__ &&
1675516780
exports.Shape = Shape;
1675616781
exports.Surface = Surface;
1675716782
exports.Text = Text;
16758-
exports.version = "19.0.0-www-classic-053b3cb0-20241115";
16783+
exports.version = "19.0.0-www-classic-92c0f5f8-20241115";
1675916784
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1676016785
"function" ===
1676116786
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

0 commit comments

Comments
 (0)