Scaffolding for useFormState (#27270)

This exposes, but does not yet implement, a new experimental API called
useFormState. It's gated behind the enableAsyncActions flag.

useFormState has a similar signature to useReducer, except instead of a
reducer it accepts an (async) action function. React will wait until the
promise resolves before updating the state:

```js
async function action(prevState, payload) {
  // ..
}
const [state, dispatch] = useFormState(action, initialState)
```

When used in combination with Server Actions, it will also support
progressive enhancement — a form that is submitted before it has
hydrated will have its state transferred to the next page. However, like
the other action-related hooks, it works with fully client-driven
actions, too.

DiffTrain build for [b4cdd3e892](https://github.com/facebook/react/commit/b4cdd3e8922713f8c9817b004a0dc51be47bc5df)
This commit is contained in:
acdlite
2023-08-23 15:05:09 +00:00
parent ff6e098a4b
commit 2bd9065dd7
21 changed files with 134 additions and 35 deletions
+1 -1
View File
@@ -1 +1 @@
31034b6de73c7cd9093e92a34e384d84c082aa4e
b4cdd3e8922713f8c9817b004a0dc51be47bc5df
+1 -1
View File
@@ -27,7 +27,7 @@ if (
}
"use strict";
var ReactVersion = "18.3.0-www-modern-a61c0c27";
var ReactVersion = "18.3.0-www-modern-fd93b451";
// ATTENTION
// When adding new symbols to this file,
+1 -1
View File
@@ -69,7 +69,7 @@ function _assertThisInitialized(self) {
return self;
}
var ReactVersion = "18.3.0-www-modern-293df28d";
var ReactVersion = "18.3.0-www-modern-3c71bf82";
var LegacyRoot = 0;
var ConcurrentRoot = 1;
@@ -9756,7 +9756,7 @@ var slice = Array.prototype.slice,
return null;
},
bundleType: 0,
version: "18.3.0-www-modern-ce3b7ded",
version: "18.3.0-www-modern-2994e97d",
rendererPackageName: "react-art"
};
var internals$jscomp$inline_1283 = {
@@ -9787,7 +9787,7 @@ var internals$jscomp$inline_1283 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-www-modern-ce3b7ded"
reconcilerVersion: "18.3.0-www-modern-2994e97d"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_1284 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -983,6 +983,11 @@ function useFormStatus() {
throw new Error("Not implemented.");
}
}
function useFormState(action, initialState, url) {
{
throw new Error("Not implemented.");
}
}
var valueStack = [];
var fiberStack;
@@ -33955,7 +33960,7 @@ function createFiberRoot(
return root;
}
var ReactVersion = "18.3.0-www-classic-ca6e9201";
var ReactVersion = "18.3.0-www-classic-763d3541";
function createPortal$1(
children,
@@ -47051,6 +47056,7 @@ assign(Internals, {
exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = Internals;
exports.createPortal = createPortal;
exports.createRoot = createRoot;
exports.experimental_useFormState = useFormState;
exports.experimental_useFormStatus = useFormStatus;
exports.findDOMNode = findDOMNode;
exports.flushSync = flushSync;
+7 -1
View File
@@ -155,6 +155,11 @@ function useFormStatus() {
throw new Error("Not implemented.");
}
}
function useFormState(action, initialState, url) {
{
throw new Error("Not implemented.");
}
}
var valueStack = [];
var fiberStack;
@@ -33800,7 +33805,7 @@ function createFiberRoot(
return root;
}
var ReactVersion = "18.3.0-www-modern-293df28d";
var ReactVersion = "18.3.0-www-modern-3c71bf82";
function createPortal$1(
children,
@@ -46120,6 +46125,7 @@ var foundDevTools = injectIntoDevTools({
exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = Internals;
exports.createPortal = createPortal;
exports.createRoot = createRoot;
exports.experimental_useFormState = useFormState;
exports.experimental_useFormStatus = useFormStatus;
exports.flushSync = flushSync;
exports.hydrateRoot = hydrateRoot;
@@ -16671,7 +16671,7 @@ Internals.Events = [
var devToolsConfig$jscomp$inline_1783 = {
findFiberByHostInstance: getClosestInstanceFromNode,
bundleType: 0,
version: "18.3.0-www-classic-bbf92da7",
version: "18.3.0-www-classic-13155cf9",
rendererPackageName: "react-dom"
};
var internals$jscomp$inline_2140 = {
@@ -16701,7 +16701,7 @@ var internals$jscomp$inline_2140 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-www-classic-bbf92da7"
reconcilerVersion: "18.3.0-www-classic-13155cf9"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_2141 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -16767,6 +16767,9 @@ exports.createRoot = function (container, options) {
);
return new ReactDOMRoot(options);
};
exports.experimental_useFormState = function () {
throw Error(formatProdErrorMessage(248));
};
exports.experimental_useFormStatus = function () {
throw Error(formatProdErrorMessage(248));
};
@@ -16937,4 +16940,4 @@ exports.unstable_renderSubtreeIntoContainer = function (
);
};
exports.unstable_runWithPriority = runWithPriority;
exports.version = "18.3.0-www-classic-bbf92da7";
exports.version = "18.3.0-www-classic-13155cf9";
@@ -16201,7 +16201,7 @@ Internals.Events = [
var devToolsConfig$jscomp$inline_1742 = {
findFiberByHostInstance: getClosestInstanceFromNode,
bundleType: 0,
version: "18.3.0-www-modern-ce3b7ded",
version: "18.3.0-www-modern-2994e97d",
rendererPackageName: "react-dom"
};
var internals$jscomp$inline_2104 = {
@@ -16232,7 +16232,7 @@ var internals$jscomp$inline_2104 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-www-modern-ce3b7ded"
reconcilerVersion: "18.3.0-www-modern-2994e97d"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_2105 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -16291,6 +16291,9 @@ exports.createRoot = function (container, options) {
);
return new ReactDOMRoot(options);
};
exports.experimental_useFormState = function () {
throw Error(formatProdErrorMessage(248));
};
exports.experimental_useFormStatus = function () {
throw Error(formatProdErrorMessage(248));
};
@@ -16396,4 +16399,4 @@ exports.unstable_createEventHandle = function (type, options) {
return eventHandle;
};
exports.unstable_runWithPriority = runWithPriority;
exports.version = "18.3.0-www-modern-ce3b7ded";
exports.version = "18.3.0-www-modern-2994e97d";
@@ -17446,7 +17446,7 @@ Internals.Events = [
var devToolsConfig$jscomp$inline_1868 = {
findFiberByHostInstance: getClosestInstanceFromNode,
bundleType: 0,
version: "18.3.0-www-classic-e408ab62",
version: "18.3.0-www-classic-4c091427",
rendererPackageName: "react-dom"
};
(function (internals) {
@@ -17490,7 +17490,7 @@ var devToolsConfig$jscomp$inline_1868 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-www-classic-e408ab62"
reconcilerVersion: "18.3.0-www-classic-4c091427"
});
assign(Internals, {
ReactBrowserEventEmitter: {
@@ -17543,6 +17543,9 @@ exports.createRoot = function (container, options) {
);
return new ReactDOMRoot(options);
};
exports.experimental_useFormState = function () {
throw Error(formatProdErrorMessage(248));
};
exports.experimental_useFormStatus = function () {
throw Error(formatProdErrorMessage(248));
};
@@ -17713,7 +17716,7 @@ exports.unstable_renderSubtreeIntoContainer = function (
);
};
exports.unstable_runWithPriority = runWithPriority;
exports.version = "18.3.0-www-classic-e408ab62";
exports.version = "18.3.0-www-classic-4c091427";
/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
if (
@@ -16970,7 +16970,7 @@ Internals.Events = [
var devToolsConfig$jscomp$inline_1827 = {
findFiberByHostInstance: getClosestInstanceFromNode,
bundleType: 0,
version: "18.3.0-www-modern-4c5a5509",
version: "18.3.0-www-modern-42b59a98",
rendererPackageName: "react-dom"
};
(function (internals) {
@@ -17015,7 +17015,7 @@ var devToolsConfig$jscomp$inline_1827 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-www-modern-4c5a5509"
reconcilerVersion: "18.3.0-www-modern-42b59a98"
});
exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = Internals;
exports.createPortal = function (children, container) {
@@ -17061,6 +17061,9 @@ exports.createRoot = function (container, options) {
);
return new ReactDOMRoot(options);
};
exports.experimental_useFormState = function () {
throw Error(formatProdErrorMessage(248));
};
exports.experimental_useFormStatus = function () {
throw Error(formatProdErrorMessage(248));
};
@@ -17166,7 +17169,7 @@ exports.unstable_createEventHandle = function (type, options) {
return eventHandle;
};
exports.unstable_runWithPriority = runWithPriority;
exports.version = "18.3.0-www-modern-4c5a5509";
exports.version = "18.3.0-www-modern-42b59a98";
/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
if (
@@ -19,7 +19,7 @@ if (__DEV__) {
var React = require("react");
var ReactDOM = require("react-dom");
var ReactVersion = "18.3.0-www-classic-dcbc1f0e";
var ReactVersion = "18.3.0-www-classic-1747ba9c";
// This refers to a WWW module.
var warningWWW = require("warning");
@@ -9563,11 +9563,20 @@ function unsupportedSetOptimisticState() {
throw new Error("Cannot update optimistic state while rendering.");
}
function unsupportedDispatchFormState() {
throw new Error("Cannot update form state while rendering.");
}
function useOptimistic(passthrough, reducer) {
resolveCurrentlyRenderingComponent();
return [passthrough, unsupportedSetOptimisticState];
}
function useFormState(action, initialState, url) {
resolveCurrentlyRenderingComponent();
return [initialState, unsupportedDispatchFormState];
}
function useId() {
var task = currentlyRenderingTask;
var treeId = getTreeId(task.treeContext);
@@ -9671,6 +9680,7 @@ var HooksDispatcher = {
if (enableAsyncActions) {
HooksDispatcher.useOptimistic = useOptimistic;
HooksDispatcher.useFormState = useFormState;
}
var currentResumableState = null;
@@ -19,7 +19,7 @@ if (__DEV__) {
var React = require("react");
var ReactDOM = require("react-dom");
var ReactVersion = "18.3.0-www-modern-55656960";
var ReactVersion = "18.3.0-www-modern-d44f2eb8";
// This refers to a WWW module.
var warningWWW = require("warning");
@@ -9322,11 +9322,20 @@ function unsupportedSetOptimisticState() {
throw new Error("Cannot update optimistic state while rendering.");
}
function unsupportedDispatchFormState() {
throw new Error("Cannot update form state while rendering.");
}
function useOptimistic(passthrough, reducer) {
resolveCurrentlyRenderingComponent();
return [passthrough, unsupportedSetOptimisticState];
}
function useFormState(action, initialState, url) {
resolveCurrentlyRenderingComponent();
return [initialState, unsupportedDispatchFormState];
}
function useId() {
var task = currentlyRenderingTask;
var treeId = getTreeId(task.treeContext);
@@ -9430,6 +9439,7 @@ var HooksDispatcher = {
if (enableAsyncActions) {
HooksDispatcher.useOptimistic = useOptimistic;
HooksDispatcher.useFormState = useFormState;
}
var currentResumableState = null;
@@ -2772,10 +2772,17 @@ function unsupportedStartTransition() {
function unsupportedSetOptimisticState() {
throw Error(formatProdErrorMessage(479));
}
function unsupportedDispatchFormState() {
throw Error(formatProdErrorMessage(485));
}
function useOptimistic(passthrough) {
resolveCurrentlyRenderingComponent();
return [passthrough, unsupportedSetOptimisticState];
}
function useFormState(action, initialState) {
resolveCurrentlyRenderingComponent();
return [initialState, unsupportedDispatchFormState];
}
function unwrapThenable(thenable) {
var index = thenableIndexCounter;
thenableIndexCounter += 1;
@@ -2870,7 +2877,9 @@ var HooksDispatcher = {
return data;
}
};
enableAsyncActions && (HooksDispatcher.useOptimistic = useOptimistic);
enableAsyncActions &&
((HooksDispatcher.useOptimistic = useOptimistic),
(HooksDispatcher.useFormState = useFormState));
var currentResumableState = null,
DefaultCacheDispatcher = {
getCacheSignal: function () {
@@ -4390,4 +4399,4 @@ exports.renderToString = function (children, options) {
'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToReadableStream" which supports Suspense on the server'
);
};
exports.version = "18.3.0-www-classic-41870992";
exports.version = "18.3.0-www-classic-4f299cee";
@@ -2764,10 +2764,17 @@ function unsupportedStartTransition() {
function unsupportedSetOptimisticState() {
throw Error(formatProdErrorMessage(479));
}
function unsupportedDispatchFormState() {
throw Error(formatProdErrorMessage(485));
}
function useOptimistic(passthrough) {
resolveCurrentlyRenderingComponent();
return [passthrough, unsupportedSetOptimisticState];
}
function useFormState(action, initialState) {
resolveCurrentlyRenderingComponent();
return [initialState, unsupportedDispatchFormState];
}
function unwrapThenable(thenable) {
var index = thenableIndexCounter;
thenableIndexCounter += 1;
@@ -2862,7 +2869,9 @@ var HooksDispatcher = {
return data;
}
};
enableAsyncActions && (HooksDispatcher.useOptimistic = useOptimistic);
enableAsyncActions &&
((HooksDispatcher.useOptimistic = useOptimistic),
(HooksDispatcher.useFormState = useFormState));
var currentResumableState = null,
DefaultCacheDispatcher = {
getCacheSignal: function () {
@@ -4373,4 +4382,4 @@ exports.renderToString = function (children, options) {
'The server used "renderToString" which does not support Suspense. If you intended for this Suspense boundary to render the fallback content on the server consider throwing an Error somewhere within the Suspense boundary. If you intended to have the server wait for the suspended component please switch to "renderToReadableStream" which supports Suspense on the server'
);
};
exports.version = "18.3.0-www-modern-8d9aaa58";
exports.version = "18.3.0-www-modern-e02b0940";
@@ -9229,11 +9229,20 @@ function unsupportedSetOptimisticState() {
throw new Error("Cannot update optimistic state while rendering.");
}
function unsupportedDispatchFormState() {
throw new Error("Cannot update form state while rendering.");
}
function useOptimistic(passthrough, reducer) {
resolveCurrentlyRenderingComponent();
return [passthrough, unsupportedSetOptimisticState];
}
function useFormState(action, initialState, url) {
resolveCurrentlyRenderingComponent();
return [initialState, unsupportedDispatchFormState];
}
function useId() {
var task = currentlyRenderingTask;
var treeId = getTreeId(task.treeContext);
@@ -9337,6 +9346,7 @@ var HooksDispatcher = {
if (enableAsyncActions) {
HooksDispatcher.useOptimistic = useOptimistic;
HooksDispatcher.useFormState = useFormState;
}
var currentResumableState = null;
@@ -2621,10 +2621,17 @@ function unsupportedStartTransition() {
function unsupportedSetOptimisticState() {
throw Error("Cannot update optimistic state while rendering.");
}
function unsupportedDispatchFormState() {
throw Error("Cannot update form state while rendering.");
}
function useOptimistic(passthrough) {
resolveCurrentlyRenderingComponent();
return [passthrough, unsupportedSetOptimisticState];
}
function useFormState(action, initialState) {
resolveCurrentlyRenderingComponent();
return [initialState, unsupportedDispatchFormState];
}
function unwrapThenable(thenable) {
var index = thenableIndexCounter;
thenableIndexCounter += 1;
@@ -2725,7 +2732,9 @@ var HooksDispatcher = {
return data;
}
};
enableAsyncActions && (HooksDispatcher.useOptimistic = useOptimistic);
enableAsyncActions &&
((HooksDispatcher.useOptimistic = useOptimistic),
(HooksDispatcher.useFormState = useFormState));
var currentResumableState = null,
DefaultCacheDispatcher = {
getCacheSignal: function () {
@@ -972,6 +972,11 @@ function useFormStatus() {
throw new Error("Not implemented.");
}
}
function useFormState(action, initialState, url) {
{
throw new Error("Not implemented.");
}
}
var valueStack = [];
var fiberStack;
@@ -34572,7 +34577,7 @@ function createFiberRoot(
return root;
}
var ReactVersion = "18.3.0-www-classic-df81fbf5";
var ReactVersion = "18.3.0-www-classic-a74a7d20";
function createPortal$1(
children,
@@ -47807,6 +47812,7 @@ exports.createRoleSelector = createRoleSelector;
exports.createRoot = createRoot;
exports.createTestNameSelector = createTestNameSelector;
exports.createTextSelector = createTextSelector;
exports.experimental_useFormState = useFormState;
exports.experimental_useFormStatus = useFormStatus;
exports.findAllNodes = findAllNodes;
exports.findBoundingRects = findBoundingRects;
@@ -144,6 +144,11 @@ function useFormStatus() {
throw new Error("Not implemented.");
}
}
function useFormState(action, initialState, url) {
{
throw new Error("Not implemented.");
}
}
var valueStack = [];
var fiberStack;
@@ -34417,7 +34422,7 @@ function createFiberRoot(
return root;
}
var ReactVersion = "18.3.0-www-modern-5039f5f3";
var ReactVersion = "18.3.0-www-modern-49db1079";
function createPortal$1(
children,
@@ -46876,6 +46881,7 @@ exports.createRoleSelector = createRoleSelector;
exports.createRoot = createRoot;
exports.createTestNameSelector = createTestNameSelector;
exports.createTextSelector = createTextSelector;
exports.experimental_useFormState = useFormState;
exports.experimental_useFormStatus = useFormStatus;
exports.findAllNodes = findAllNodes;
exports.findBoundingRects = findBoundingRects;
@@ -17000,7 +17000,7 @@ Internals.Events = [
var devToolsConfig$jscomp$inline_1812 = {
findFiberByHostInstance: getClosestInstanceFromNode,
bundleType: 0,
version: "18.3.0-www-classic-3a93fd0f",
version: "18.3.0-www-classic-6a0bb38f",
rendererPackageName: "react-dom"
};
var internals$jscomp$inline_2174 = {
@@ -17030,7 +17030,7 @@ var internals$jscomp$inline_2174 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-www-classic-3a93fd0f"
reconcilerVersion: "18.3.0-www-classic-6a0bb38f"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_2175 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -17111,6 +17111,9 @@ exports.createTestNameSelector = function (id) {
exports.createTextSelector = function (text) {
return { $$typeof: TEXT_TYPE, value: text };
};
exports.experimental_useFormState = function () {
throw Error(formatProdErrorMessage(248));
};
exports.experimental_useFormStatus = function () {
throw Error(formatProdErrorMessage(248));
};
@@ -17417,4 +17420,4 @@ exports.unstable_renderSubtreeIntoContainer = function (
);
};
exports.unstable_runWithPriority = runWithPriority;
exports.version = "18.3.0-www-classic-3a93fd0f";
exports.version = "18.3.0-www-classic-6a0bb38f";
@@ -16585,7 +16585,7 @@ Internals.Events = [
var devToolsConfig$jscomp$inline_1771 = {
findFiberByHostInstance: getClosestInstanceFromNode,
bundleType: 0,
version: "18.3.0-www-modern-a61c0c27",
version: "18.3.0-www-modern-fd93b451",
rendererPackageName: "react-dom"
};
var internals$jscomp$inline_2138 = {
@@ -16616,7 +16616,7 @@ var internals$jscomp$inline_2138 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-www-modern-a61c0c27"
reconcilerVersion: "18.3.0-www-modern-fd93b451"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_2139 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -16690,6 +16690,9 @@ exports.createTestNameSelector = function (id) {
exports.createTextSelector = function (text) {
return { $$typeof: TEXT_TYPE, value: text };
};
exports.experimental_useFormState = function () {
throw Error(formatProdErrorMessage(248));
};
exports.experimental_useFormStatus = function () {
throw Error(formatProdErrorMessage(248));
};
@@ -16931,4 +16934,4 @@ exports.unstable_createEventHandle = function (type, options) {
return eventHandle;
};
exports.unstable_runWithPriority = runWithPriority;
exports.version = "18.3.0-www-modern-a61c0c27";
exports.version = "18.3.0-www-modern-fd93b451";
@@ -24339,7 +24339,7 @@ function createFiberRoot(
return root;
}
var ReactVersion = "18.3.0-www-classic-df81fbf5";
var ReactVersion = "18.3.0-www-classic-a74a7d20";
// Might add PROFILE later.