Warn if optimistic state is updated outside of a transition (#27454)

### Based on #27453

If optimistic state is updated, and there's no startTransition on the
stack, there are two likely scenarios.

One possibility is that the optimistic update is triggered by a regular
event handler (e.g. `onSubmit`) instead of an action. This is a mistake
and we will warn.

The other possibility is the optimistic update is inside an async
action, but after an `await`. In this case, we can make it "just work"
by associating the optimistic update with the pending async action.

Technically it's possible that the optimistic update is unrelated to the
pending action, but we don't have a way of knowing this for sure because
browsers currently do not provide a way to track async scope. (The
AsyncContext proposal, if it lands, will solve this in the future.)
However, this is no different than the problem of unrelated transitions
being grouped together — it's not wrong per se, but it's not ideal.

Once AsyncContext starts landing in browsers, we will provide better
warnings in development for these cases.

DiffTrain build for commit https://github.com/facebook/react/commit/88d56b8e818d0c48eb6642303169c1fadeb99d59.
This commit is contained in:
acdlite
2023-10-04 15:03:01 +00:00
parent 6f227fff64
commit be884f084a
9 changed files with 20 additions and 20 deletions
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<d08221cdf198c30256d8574839ecbf7a>>
* @generated SignedSource<<85d4c20d55cfdfd42f825208f96c046d>>
*/
'use strict';
@@ -8153,14 +8153,14 @@ function startTransition(
higherEventPriority(previousPriority, ContinuousEventPriority)
);
var prevTransition = ReactCurrentBatchConfig$2.transition;
var currentTransition = {};
{
ReactCurrentBatchConfig$2.transition = null;
dispatchSetState(fiber, queue, pendingState);
ReactCurrentBatchConfig$2.transition = currentTransition;
}
var currentTransition = (ReactCurrentBatchConfig$2.transition = {});
{
ReactCurrentBatchConfig$2.transition._updatedFibers = new Set();
}
@@ -23997,7 +23997,7 @@ function createFiberRoot(
return root;
}
var ReactVersion = "18.3.0-canary-bd6891742-20231004";
var ReactVersion = "18.3.0-canary-88d56b8e8-20231004";
// Might add PROFILE later.
@@ -8623,7 +8623,7 @@ var devToolsConfig$jscomp$inline_1030 = {
throw Error("TestRenderer does not support findFiberByHostInstance()");
},
bundleType: 0,
version: "18.3.0-canary-bd6891742-20231004",
version: "18.3.0-canary-88d56b8e8-20231004",
rendererPackageName: "react-test-renderer"
};
var internals$jscomp$inline_1229 = {
@@ -8654,7 +8654,7 @@ var internals$jscomp$inline_1229 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-canary-bd6891742-20231004"
reconcilerVersion: "18.3.0-canary-88d56b8e8-20231004"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_1230 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -9049,7 +9049,7 @@ var devToolsConfig$jscomp$inline_1072 = {
throw Error("TestRenderer does not support findFiberByHostInstance()");
},
bundleType: 0,
version: "18.3.0-canary-bd6891742-20231004",
version: "18.3.0-canary-88d56b8e8-20231004",
rendererPackageName: "react-test-renderer"
};
var internals$jscomp$inline_1270 = {
@@ -9080,7 +9080,7 @@ var internals$jscomp$inline_1270 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-canary-bd6891742-20231004"
reconcilerVersion: "18.3.0-canary-88d56b8e8-20231004"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_1271 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -27,7 +27,7 @@ if (
}
"use strict";
var ReactVersion = "18.3.0-canary-bd6891742-20231004";
var ReactVersion = "18.3.0-canary-88d56b8e8-20231004";
// ATTENTION
// When adding new symbols to this file,
@@ -616,4 +616,4 @@ exports.useSyncExternalStore = function (
exports.useTransition = function () {
return ReactCurrentDispatcher.current.useTransition();
};
exports.version = "18.3.0-canary-bd6891742-20231004";
exports.version = "18.3.0-canary-88d56b8e8-20231004";
@@ -619,7 +619,7 @@ exports.useSyncExternalStore = function (
exports.useTransition = function () {
return ReactCurrentDispatcher.current.useTransition();
};
exports.version = "18.3.0-canary-bd6891742-20231004";
exports.version = "18.3.0-canary-88d56b8e8-20231004";
/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
if (
@@ -1 +1 @@
bd6891742c606a4b8d6ce53760218c6ab3784b38
88d56b8e818d0c48eb6642303169c1fadeb99d59
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<c7798d7e49297e588bffdcccc6aa6cb9>>
* @generated SignedSource<<d547d784dfd2ff8ab9a6adadb432b1cc>>
*/
'use strict';
@@ -12065,14 +12065,14 @@ function startTransition(
higherEventPriority(previousPriority, ContinuousEventPriority)
);
var prevTransition = ReactCurrentBatchConfig$2.transition;
var currentTransition = {};
{
ReactCurrentBatchConfig$2.transition = null;
dispatchSetState(fiber, queue, pendingState);
ReactCurrentBatchConfig$2.transition = currentTransition;
}
var currentTransition = (ReactCurrentBatchConfig$2.transition = {});
{
ReactCurrentBatchConfig$2.transition._updatedFibers = new Set();
}
@@ -27063,7 +27063,7 @@ function createFiberRoot(
return root;
}
var ReactVersion = "18.3.0-canary-4227b2ef";
var ReactVersion = "18.3.0-canary-112791ea";
function createPortal$1(
children,
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<4d93f2723dd9dce45836c9aa389d421c>>
* @generated SignedSource<<543fb8317c4df4706b2ce72a1d3b1115>>
*/
'use strict';
@@ -12361,14 +12361,14 @@ function startTransition(
higherEventPriority(previousPriority, ContinuousEventPriority)
);
var prevTransition = ReactCurrentBatchConfig$2.transition;
var currentTransition = {};
{
ReactCurrentBatchConfig$2.transition = null;
dispatchSetState(fiber, queue, pendingState);
ReactCurrentBatchConfig$2.transition = currentTransition;
}
var currentTransition = (ReactCurrentBatchConfig$2.transition = {});
{
ReactCurrentBatchConfig$2.transition._updatedFibers = new Set();
}
@@ -27553,7 +27553,7 @@ function createFiberRoot(
return root;
}
var ReactVersion = "18.3.0-canary-35bc08a0";
var ReactVersion = "18.3.0-canary-7f160471";
function createPortal$1(
children,