Skip to content

Commit 43fc2ba

Browse files
committed
useFormState: Reuse state from previous form submission (#27321)
If a Server Action is passed to useFormState, the action may be submitted before it has hydrated. This will trigger a full page (MPA-style) navigation. We can transfer the form state to the next page by comparing the key path of the hook instance. `ReactServerDOMServer.decodeFormState` is used by the server to extract the form state from the submitted action. This value can then be passed as an option when rendering the new page. It must be passed during both SSR and hydration. ```js const boundAction = await decodeAction(formData, serverManifest); const result = await boundAction(); const formState = decodeFormState(result, formData, serverManifest); // SSR const response = createFromReadableStream(<App />); const ssrStream = await renderToReadableStream(response, { formState }) // Hydration hydrateRoot(container, <App />, { formState }); ``` If the `formState` option is omitted, then the state won't be transferred to the next page. However, it must be passed in both places, or in neither; misconfiguring will result in a hydration mismatch. (The `formState` option is currently prefixed with `experimental_`) DiffTrain build for [612b2b6](612b2b6)
1 parent a1e1701 commit 43fc2ba

25 files changed

+637
-251
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
e5205658f40ad181279857dbb66e36b8ebcd8c0e
1+
612b2b6601abb844248c384d1e288bb824b180b7

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ if (
2727
}
2828
"use strict";
2929

30-
var ReactVersion = "18.3.0-www-classic-06724970";
30+
var ReactVersion = "18.3.0-www-classic-d9972e1c";
3131

3232
// ATTENTION
3333
// When adding new symbols to this file,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ if (
2727
}
2828
"use strict";
2929

30-
var ReactVersion = "18.3.0-www-modern-5ff32fc3";
30+
var ReactVersion = "18.3.0-www-modern-e51d03c9";
3131

3232
// ATTENTION
3333
// When adding new symbols to this file,

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function _assertThisInitialized(self) {
6969
return self;
7070
}
7171

72-
var ReactVersion = "18.3.0-www-classic-bb068684";
72+
var ReactVersion = "18.3.0-www-classic-4de809d2";
7373

7474
var LegacyRoot = 0;
7575
var ConcurrentRoot = 1;
@@ -28256,7 +28256,8 @@ function FiberRootNode(
2825628256
tag,
2825728257
hydrate,
2825828258
identifierPrefix,
28259-
onRecoverableError
28259+
onRecoverableError,
28260+
formState
2826028261
) {
2826128262
this.tag = tag;
2826228263
this.containerInfo = containerInfo;
@@ -28294,6 +28295,7 @@ function FiberRootNode(
2829428295
this.hydrationCallbacks = null;
2829528296
}
2829628297

28298+
this.formState = formState;
2829728299
this.incompleteTransitions = new Map();
2829828300

2829928301
if (enableTransitionTracing) {
@@ -28345,15 +28347,17 @@ function createFiberRoot(
2834528347
// single type, like a DynamicHostConfig that is defined by the renderer.
2834628348
identifierPrefix,
2834728349
onRecoverableError,
28348-
transitionCallbacks
28350+
transitionCallbacks,
28351+
formState
2834928352
) {
2835028353
// $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions
2835128354
var root = new FiberRootNode(
2835228355
containerInfo,
2835328356
tag,
2835428357
hydrate,
2835528358
identifierPrefix,
28356-
onRecoverableError
28359+
onRecoverableError,
28360+
formState
2835728361
);
2835828362

2835928363
{
@@ -28446,7 +28450,8 @@ function createContainer(
2844628450
concurrentUpdatesByDefaultOverride,
2844728451
identifierPrefix,
2844828452
onRecoverableError,
28449-
transitionCallbacks
28453+
transitionCallbacks,
28454+
null
2845028455
);
2845128456
}
2845228457
function updateContainer(element, container, parentComponent, callback) {

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function _assertThisInitialized(self) {
6969
return self;
7070
}
7171

72-
var ReactVersion = "18.3.0-www-modern-dcc12554";
72+
var ReactVersion = "18.3.0-www-modern-d6fa9db4";
7373

7474
var LegacyRoot = 0;
7575
var ConcurrentRoot = 1;
@@ -27916,7 +27916,8 @@ function FiberRootNode(
2791627916
tag,
2791727917
hydrate,
2791827918
identifierPrefix,
27919-
onRecoverableError
27919+
onRecoverableError,
27920+
formState
2792027921
) {
2792127922
this.tag = tag;
2792227923
this.containerInfo = containerInfo;
@@ -27954,6 +27955,7 @@ function FiberRootNode(
2795427955
this.hydrationCallbacks = null;
2795527956
}
2795627957

27958+
this.formState = formState;
2795727959
this.incompleteTransitions = new Map();
2795827960

2795927961
if (enableTransitionTracing) {
@@ -28005,15 +28007,17 @@ function createFiberRoot(
2800528007
// single type, like a DynamicHostConfig that is defined by the renderer.
2800628008
identifierPrefix,
2800728009
onRecoverableError,
28008-
transitionCallbacks
28010+
transitionCallbacks,
28011+
formState
2800928012
) {
2801028013
// $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions
2801128014
var root = new FiberRootNode(
2801228015
containerInfo,
2801328016
tag,
2801428017
hydrate,
2801528018
identifierPrefix,
28016-
onRecoverableError
28019+
onRecoverableError,
28020+
formState
2801728021
);
2801828022

2801928023
{
@@ -28106,7 +28110,8 @@ function createContainer(
2810628110
concurrentUpdatesByDefaultOverride,
2810728111
identifierPrefix,
2810828112
onRecoverableError,
28109-
transitionCallbacks
28113+
transitionCallbacks,
28114+
null
2811028115
);
2811128116
}
2811228117
function updateContainer(element, container, parentComponent, callback) {

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

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9890,7 +9890,8 @@ function FiberRootNode(
98909890
tag,
98919891
hydrate,
98929892
identifierPrefix,
9893-
onRecoverableError
9893+
onRecoverableError,
9894+
formState
98949895
) {
98959896
this.tag = tag;
98969897
this.containerInfo = containerInfo;
@@ -9924,6 +9925,7 @@ function FiberRootNode(
99249925
this.pooledCache = null;
99259926
this.pooledCacheLanes = 0;
99269927
this.hydrationCallbacks = null;
9928+
this.formState = formState;
99279929
this.incompleteTransitions = new Map();
99289930
if (enableTransitionTracing)
99299931
for (
@@ -10036,7 +10038,7 @@ var slice = Array.prototype.slice,
1003610038
+_this$props.height,
1003710039
this._tagRef
1003810040
);
10039-
_this$props = new FiberRootNode(this._surface, 0, !1, "", void 0);
10041+
_this$props = new FiberRootNode(this._surface, 0, !1, "", void 0, null);
1004010042
_this$props.hydrationCallbacks = null;
1004110043
enableTransitionTracing && (_this$props.transitionCallbacks = void 0);
1004210044
var JSCompiler_inline_result = createFiber(3, null, null, 0);
@@ -10115,10 +10117,10 @@ var slice = Array.prototype.slice,
1011510117
return null;
1011610118
},
1011710119
bundleType: 0,
10118-
version: "18.3.0-www-classic-06724970",
10120+
version: "18.3.0-www-classic-d9972e1c",
1011910121
rendererPackageName: "react-art"
1012010122
};
10121-
var internals$jscomp$inline_1302 = {
10123+
var internals$jscomp$inline_1303 = {
1012210124
bundleType: devToolsConfig$jscomp$inline_1130.bundleType,
1012310125
version: devToolsConfig$jscomp$inline_1130.version,
1012410126
rendererPackageName: devToolsConfig$jscomp$inline_1130.rendererPackageName,
@@ -10146,19 +10148,19 @@ var internals$jscomp$inline_1302 = {
1014610148
scheduleRoot: null,
1014710149
setRefreshHandler: null,
1014810150
getCurrentFiber: null,
10149-
reconcilerVersion: "18.3.0-www-classic-06724970"
10151+
reconcilerVersion: "18.3.0-www-classic-d9972e1c"
1015010152
};
1015110153
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
10152-
var hook$jscomp$inline_1303 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
10154+
var hook$jscomp$inline_1304 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
1015310155
if (
10154-
!hook$jscomp$inline_1303.isDisabled &&
10155-
hook$jscomp$inline_1303.supportsFiber
10156+
!hook$jscomp$inline_1304.isDisabled &&
10157+
hook$jscomp$inline_1304.supportsFiber
1015610158
)
1015710159
try {
10158-
(rendererID = hook$jscomp$inline_1303.inject(
10159-
internals$jscomp$inline_1302
10160+
(rendererID = hook$jscomp$inline_1304.inject(
10161+
internals$jscomp$inline_1303
1016010162
)),
10161-
(injectedHook = hook$jscomp$inline_1303);
10163+
(injectedHook = hook$jscomp$inline_1304);
1016210164
} catch (err) {}
1016310165
}
1016410166
var Path = Mode$1.Path;

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

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9595,7 +9595,8 @@ function FiberRootNode(
95959595
tag,
95969596
hydrate,
95979597
identifierPrefix,
9598-
onRecoverableError
9598+
onRecoverableError,
9599+
formState
95999600
) {
96009601
this.tag = tag;
96019602
this.containerInfo = containerInfo;
@@ -9629,6 +9630,7 @@ function FiberRootNode(
96299630
this.pooledCache = null;
96309631
this.pooledCacheLanes = 0;
96319632
this.hydrationCallbacks = null;
9633+
this.formState = formState;
96329634
this.incompleteTransitions = new Map();
96339635
if (enableTransitionTracing)
96349636
for (
@@ -9701,7 +9703,7 @@ var slice = Array.prototype.slice,
97019703
+_this$props.height,
97029704
this._tagRef
97039705
);
9704-
_this$props = new FiberRootNode(this._surface, 0, !1, "", void 0);
9706+
_this$props = new FiberRootNode(this._surface, 0, !1, "", void 0, null);
97059707
_this$props.hydrationCallbacks = null;
97069708
enableTransitionTracing && (_this$props.transitionCallbacks = void 0);
97079709
var JSCompiler_inline_result = createFiber(3, null, null, 0);
@@ -9780,10 +9782,10 @@ var slice = Array.prototype.slice,
97809782
return null;
97819783
},
97829784
bundleType: 0,
9783-
version: "18.3.0-www-modern-ca0ea9bc",
9785+
version: "18.3.0-www-modern-06894e4c",
97849786
rendererPackageName: "react-art"
97859787
};
9786-
var internals$jscomp$inline_1282 = {
9788+
var internals$jscomp$inline_1283 = {
97879789
bundleType: devToolsConfig$jscomp$inline_1110.bundleType,
97889790
version: devToolsConfig$jscomp$inline_1110.version,
97899791
rendererPackageName: devToolsConfig$jscomp$inline_1110.rendererPackageName,
@@ -9811,19 +9813,19 @@ var internals$jscomp$inline_1282 = {
98119813
scheduleRoot: null,
98129814
setRefreshHandler: null,
98139815
getCurrentFiber: null,
9814-
reconcilerVersion: "18.3.0-www-modern-ca0ea9bc"
9816+
reconcilerVersion: "18.3.0-www-modern-06894e4c"
98159817
};
98169818
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
9817-
var hook$jscomp$inline_1283 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
9819+
var hook$jscomp$inline_1284 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
98189820
if (
9819-
!hook$jscomp$inline_1283.isDisabled &&
9820-
hook$jscomp$inline_1283.supportsFiber
9821+
!hook$jscomp$inline_1284.isDisabled &&
9822+
hook$jscomp$inline_1284.supportsFiber
98219823
)
98229824
try {
9823-
(rendererID = hook$jscomp$inline_1283.inject(
9824-
internals$jscomp$inline_1282
9825+
(rendererID = hook$jscomp$inline_1284.inject(
9826+
internals$jscomp$inline_1283
98259827
)),
9826-
(injectedHook = hook$jscomp$inline_1283);
9828+
(injectedHook = hook$jscomp$inline_1284);
98279829
} catch (err) {}
98289830
}
98299831
var Path = Mode$1.Path;

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

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33868,7 +33868,8 @@ function FiberRootNode(
3386833868
tag,
3386933869
hydrate,
3387033870
identifierPrefix,
33871-
onRecoverableError
33871+
onRecoverableError,
33872+
formState
3387233873
) {
3387333874
this.tag = tag;
3387433875
this.containerInfo = containerInfo;
@@ -33906,6 +33907,7 @@ function FiberRootNode(
3390633907
this.hydrationCallbacks = null;
3390733908
}
3390833909

33910+
this.formState = formState;
3390933911
this.incompleteTransitions = new Map();
3391033912

3391133913
if (enableTransitionTracing) {
@@ -33957,15 +33959,17 @@ function createFiberRoot(
3395733959
// single type, like a DynamicHostConfig that is defined by the renderer.
3395833960
identifierPrefix,
3395933961
onRecoverableError,
33960-
transitionCallbacks
33962+
transitionCallbacks,
33963+
formState
3396133964
) {
3396233965
// $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions
3396333966
var root = new FiberRootNode(
3396433967
containerInfo,
3396533968
tag,
3396633969
hydrate,
3396733970
identifierPrefix,
33968-
onRecoverableError
33971+
onRecoverableError,
33972+
formState
3396933973
);
3397033974

3397133975
{
@@ -34009,7 +34013,7 @@ function createFiberRoot(
3400934013
return root;
3401034014
}
3401134015

34012-
var ReactVersion = "18.3.0-www-classic-6066e798";
34016+
var ReactVersion = "18.3.0-www-classic-8517a3ec";
3401334017

3401434018
function createPortal$1(
3401534019
children,
@@ -34154,7 +34158,8 @@ function createContainer(
3415434158
concurrentUpdatesByDefaultOverride,
3415534159
identifierPrefix,
3415634160
onRecoverableError,
34157-
transitionCallbacks
34161+
transitionCallbacks,
34162+
null
3415834163
);
3415934164
}
3416034165
function createHydrationContainer(
@@ -34167,7 +34172,8 @@ function createHydrationContainer(
3416734172
concurrentUpdatesByDefaultOverride,
3416834173
identifierPrefix,
3416934174
onRecoverableError,
34170-
transitionCallbacks
34175+
transitionCallbacks,
34176+
formState
3417134177
) {
3417234178
var hydrate = true;
3417334179
var root = createFiberRoot(
@@ -34180,7 +34186,8 @@ function createHydrationContainer(
3418034186
concurrentUpdatesByDefaultOverride,
3418134187
identifierPrefix,
3418234188
onRecoverableError,
34183-
transitionCallbacks
34189+
transitionCallbacks,
34190+
formState
3418434191
); // TODO: Move this to FiberRoot constructor
3418534192

3418634193
root.context = getContextForSubtree(null); // Schedule the initial render. In a hydration root, this is different from
@@ -46016,6 +46023,7 @@ function hydrateRoot$1(container, initialChildren, options) {
4601646023
var identifierPrefix = "";
4601746024
var onRecoverableError = defaultOnRecoverableError;
4601846025
var transitionCallbacks = null;
46026+
var formState = null;
4601946027

4602046028
if (options !== null && options !== undefined) {
4602146029
if (options.unstable_strictMode === true) {
@@ -46037,6 +46045,12 @@ function hydrateRoot$1(container, initialChildren, options) {
4603746045
if (options.unstable_transitionCallbacks !== undefined) {
4603846046
transitionCallbacks = options.unstable_transitionCallbacks;
4603946047
}
46048+
46049+
if (enableAsyncActions && enableFormActions) {
46050+
if (options.experimental_formState !== undefined) {
46051+
formState = options.experimental_formState;
46052+
}
46053+
}
4604046054
}
4604146055

4604246056
var root = createHydrationContainer(
@@ -46049,7 +46063,8 @@ function hydrateRoot$1(container, initialChildren, options) {
4604946063
concurrentUpdatesByDefaultOverride,
4605046064
identifierPrefix,
4605146065
onRecoverableError,
46052-
transitionCallbacks
46066+
transitionCallbacks,
46067+
formState
4605346068
);
4605446069
markContainerAsRoot(root.current, container);
4605546070
Dispatcher$1.current = ReactDOMClientDispatcher; // This can't be a comment node since hydration doesn't work on comment nodes anyway.
@@ -46181,6 +46196,7 @@ function legacyCreateRootFromDOMContainer(
4618146196
false, // concurrentUpdatesByDefaultOverride,
4618246197
"", // identifierPrefix
4618346198
noopOnRecoverableError, // TODO(luna) Support hydration later
46199+
null,
4618446200
null
4618546201
);
4618646202
container._reactRootContainer = root;

0 commit comments

Comments
 (0)