Skip to content

Commit 79eaef5

Browse files
committed
Client implementation of useFormState (#27278)
This implements useFormState in Fiber. (It does not include any progressive enhancement features; those will be added later.) useFormState is a hook for tracking state produced by async actions. It has a signature similar to useReducer, but instead of a reducer, it accepts an async action function. ```js async function action(prevState, payload) { // .. } const [state, dispatch] = useFormState(action, initialState) ``` Calling dispatch runs the async action and updates the state to the returned value. Async actions run before React's render cycle, so unlike reducers, they can contain arbitrary side effects. DiffTrain build for commit 456d153.
1 parent e059d6a commit 79eaef5

13 files changed

Lines changed: 778 additions & 763 deletions

File tree

compiled-rn/facebook-fbsource/xplat/js/RKJSModules/vendor/react-test-renderer/cjs/ReactTestRenderer-dev.js

Lines changed: 91 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @noflow
88
* @nolint
99
* @preventMunge
10-
* @generated SignedSource<<c9230720afe9095de02a7a43b74e1202>>
10+
* @generated SignedSource<<3545510f0ae198cd36a14af654d7cf69>>
1111
*/
1212

1313
'use strict';
@@ -6409,97 +6409,102 @@ var currentEntangledListeners = null; // The number of pending async actions in
64096409
var currentEntangledPendingCount = 0; // The transition lane shared by all updates in the entangled scope.
64106410

64116411
var currentEntangledLane = NoLane;
6412-
function requestAsyncActionContext(actionReturnValue, finishedState) {
6413-
if (
6414-
actionReturnValue !== null &&
6415-
typeof actionReturnValue === "object" &&
6416-
typeof actionReturnValue.then === "function"
6417-
) {
6418-
// This is an async action.
6419-
//
6420-
// Return a thenable that resolves once the action scope (i.e. the async
6421-
// function passed to startTransition) has finished running.
6422-
var thenable = actionReturnValue;
6423-
var entangledListeners;
6424-
6425-
if (currentEntangledListeners === null) {
6426-
// There's no outer async action scope. Create a new one.
6427-
entangledListeners = currentEntangledListeners = [];
6428-
currentEntangledPendingCount = 0;
6429-
currentEntangledLane = requestTransitionLane();
6430-
} else {
6431-
entangledListeners = currentEntangledListeners;
6412+
function requestAsyncActionContext(
6413+
actionReturnValue, // If this is provided, this resulting thenable resolves to this value instead
6414+
// of the return value of the action. This is a perf trick to avoid composing
6415+
// an extra async function.
6416+
overrideReturnValue
6417+
) {
6418+
// This is an async action.
6419+
//
6420+
// Return a thenable that resolves once the action scope (i.e. the async
6421+
// function passed to startTransition) has finished running.
6422+
var thenable = actionReturnValue;
6423+
var entangledListeners;
6424+
6425+
if (currentEntangledListeners === null) {
6426+
// There's no outer async action scope. Create a new one.
6427+
entangledListeners = currentEntangledListeners = [];
6428+
currentEntangledPendingCount = 0;
6429+
currentEntangledLane = requestTransitionLane();
6430+
} else {
6431+
entangledListeners = currentEntangledListeners;
6432+
}
6433+
6434+
currentEntangledPendingCount++; // Create a thenable that represents the result of this action, but doesn't
6435+
// resolve until the entire entangled scope has finished.
6436+
//
6437+
// Expressed using promises:
6438+
// const [thisResult] = await Promise.all([thisAction, entangledAction]);
6439+
// return thisResult;
6440+
6441+
var resultThenable = createResultThenable(entangledListeners);
6442+
var resultStatus = "pending";
6443+
var resultValue;
6444+
var rejectedReason;
6445+
thenable.then(
6446+
function (value) {
6447+
resultStatus = "fulfilled";
6448+
resultValue = overrideReturnValue !== null ? overrideReturnValue : value;
6449+
pingEngtangledActionScope();
6450+
},
6451+
function (error) {
6452+
resultStatus = "rejected";
6453+
rejectedReason = error;
6454+
pingEngtangledActionScope();
64326455
}
6456+
); // Attach a listener to fill in the result.
64336457

6434-
currentEntangledPendingCount++;
6435-
var resultStatus = "pending";
6436-
var rejectedReason;
6437-
thenable.then(
6438-
function () {
6439-
resultStatus = "fulfilled";
6440-
pingEngtangledActionScope();
6441-
},
6442-
function (error) {
6443-
resultStatus = "rejected";
6444-
rejectedReason = error;
6445-
pingEngtangledActionScope();
6458+
entangledListeners.push(function () {
6459+
switch (resultStatus) {
6460+
case "fulfilled": {
6461+
var fulfilledThenable = resultThenable;
6462+
fulfilledThenable.status = "fulfilled";
6463+
fulfilledThenable.value = resultValue;
6464+
break;
64466465
}
6447-
); // Create a thenable that represents the result of this action, but doesn't
6448-
// resolve until the entire entangled scope has finished.
6449-
//
6450-
// Expressed using promises:
6451-
// const [thisResult] = await Promise.all([thisAction, entangledAction]);
6452-
// return thisResult;
64536466

6454-
var resultThenable = createResultThenable(entangledListeners); // Attach a listener to fill in the result.
6455-
6456-
entangledListeners.push(function () {
6457-
switch (resultStatus) {
6458-
case "fulfilled": {
6459-
var fulfilledThenable = resultThenable;
6460-
fulfilledThenable.status = "fulfilled";
6461-
fulfilledThenable.value = finishedState;
6462-
break;
6463-
}
6464-
6465-
case "rejected": {
6466-
var rejectedThenable = resultThenable;
6467-
rejectedThenable.status = "rejected";
6468-
rejectedThenable.reason = rejectedReason;
6469-
break;
6470-
}
6467+
case "rejected": {
6468+
var rejectedThenable = resultThenable;
6469+
rejectedThenable.status = "rejected";
6470+
rejectedThenable.reason = rejectedReason;
6471+
break;
6472+
}
64716473

6472-
case "pending":
6473-
default: {
6474-
// The listener above should have been called first, so `resultStatus`
6475-
// should already be set to the correct value.
6476-
throw new Error(
6477-
"Thenable should have already resolved. This " +
6478-
"is a bug in React."
6479-
);
6480-
}
6474+
case "pending":
6475+
default: {
6476+
// The listener above should have been called first, so `resultStatus`
6477+
// should already be set to the correct value.
6478+
throw new Error(
6479+
"Thenable should have already resolved. This " + "is a bug in React."
6480+
);
64816481
}
6482+
}
6483+
});
6484+
return resultThenable;
6485+
}
6486+
function requestSyncActionContext(
6487+
actionReturnValue, // If this is provided, this resulting thenable resolves to this value instead
6488+
// of the return value of the action. This is a perf trick to avoid composing
6489+
// an extra async function.
6490+
overrideReturnValue
6491+
) {
6492+
var resultValue =
6493+
overrideReturnValue !== null ? overrideReturnValue : actionReturnValue; // This is not an async action, but it may be part of an outer async action.
6494+
6495+
if (currentEntangledListeners === null) {
6496+
return resultValue;
6497+
} else {
6498+
// Return a thenable that does not resolve until the entangled actions
6499+
// have finished.
6500+
var entangledListeners = currentEntangledListeners;
6501+
var resultThenable = createResultThenable(entangledListeners);
6502+
entangledListeners.push(function () {
6503+
var fulfilledThenable = resultThenable;
6504+
fulfilledThenable.status = "fulfilled";
6505+
fulfilledThenable.value = resultValue;
64826506
});
64836507
return resultThenable;
6484-
} else {
6485-
// This is not an async action, but it may be part of an outer async action.
6486-
if (currentEntangledListeners === null) {
6487-
return finishedState;
6488-
} else {
6489-
// Return a thenable that does not resolve until the entangled actions
6490-
// have finished.
6491-
var _entangledListeners = currentEntangledListeners;
6492-
6493-
var _resultThenable = createResultThenable(_entangledListeners);
6494-
6495-
_entangledListeners.push(function () {
6496-
var fulfilledThenable = _resultThenable;
6497-
fulfilledThenable.status = "fulfilled";
6498-
fulfilledThenable.value = finishedState;
6499-
});
6500-
6501-
return _resultThenable;
6502-
}
65036508
}
65046509
}
65056510

@@ -8160,7 +8165,7 @@ function startTransition(
81608165
}
81618166

81628167
try {
8163-
var returnValue, maybeThenable;
8168+
var returnValue, thenable, entangledResult, _entangledResult;
81648169
if (enableAsyncActions);
81658170
else {
81668171
// Async actions are not enabled.
@@ -23981,7 +23986,7 @@ function createFiberRoot(
2398123986
return root;
2398223987
}
2398323988

23984-
var ReactVersion = "18.3.0-canary-9a01c8b54-20230828";
23989+
var ReactVersion = "18.3.0-canary-456d153bb-20230828";
2398523990

2398623991
// Might add PROFILE later.
2398723992

0 commit comments

Comments
 (0)