You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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)
function checkIfUseWrappedInAsyncCatch(rejectedReason) {
2808
-
if (rejectedReason === SuspenseException)
2809
+
if (
2810
+
rejectedReason === SuspenseException ||
2811
+
rejectedReason === SuspenseActionException
2812
+
)
2809
2813
throw Error(
2810
2814
"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."
2811
2815
);
@@ -3827,7 +3831,7 @@ __DEV__ &&
3827
3831
thenableState$1 = null;
3828
3832
return firstChildFiber;
3829
3833
} catch (x) {
3830
-
if (x === SuspenseException) throw x;
3834
+
if (x === SuspenseException || x === SuspenseActionException) throw x;
3831
3835
var fiber = createFiber(29, x, null, returnFiber.mode);
3832
3836
fiber.lanes = lanes;
3833
3837
fiber.return = returnFiber;
@@ -4918,24 +4922,30 @@ __DEV__ &&
4918
4922
actionStateReducer
4919
4923
)[0];
4920
4924
stateHook = updateReducer(basicStateReducer)[0];
4921
-
currentStateHook =
4925
+
if (
4922
4926
"object" === typeof currentStateHook &&
4923
4927
null !== currentStateHook &&
4924
4928
"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;
"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`."
14887
14908
),
14888
14909
SuspenseyCommitException = Error(
14889
14910
"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."
14890
14911
),
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."
0 commit comments