Skip to content

Commit

Permalink
Add pending state to useFormState (#28514)
Browse files Browse the repository at this point in the history
## Overview

Adds a `pending` state to useFormState, which will be replaced by
`useActionState` in the next diff. We will keep `useFormState` around
for backwards compatibility, but functionally it will work the same as
`useActionState`, which has an `isPending` state returned.

DiffTrain build for [17eaaca](17eaaca)
  • Loading branch information
rickhanlonii committed Mar 12, 2024
1 parent 43ce284 commit 8e12d48
Show file tree
Hide file tree
Showing 27 changed files with 966 additions and 371 deletions.
2 changes: 1 addition & 1 deletion compiled/facebook-www/REVISION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3e6bc7d2d7098d9c8a30ba6e7a877df70f4d8d34
17eaacaac167addf0c4358b4983f054073a0626d
2 changes: 1 addition & 1 deletion compiled/facebook-www/React-prod.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -633,4 +633,4 @@ exports.useSyncExternalStore = function (
exports.useTransition = function () {
return ReactCurrentDispatcher.current.useTransition();
};
exports.version = "18.3.0-www-classic-43ac25ba";
exports.version = "18.3.0-www-classic-7c2abefb";
2 changes: 1 addition & 1 deletion compiled/facebook-www/React-prod.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -625,4 +625,4 @@ exports.useSyncExternalStore = function (
exports.useTransition = function () {
return ReactCurrentDispatcher.current.useTransition();
};
exports.version = "18.3.0-www-modern-a7ff7332";
exports.version = "18.3.0-www-modern-0337b6c3";
2 changes: 1 addition & 1 deletion compiled/facebook-www/React-profiling.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ exports.useSyncExternalStore = function (
exports.useTransition = function () {
return ReactCurrentDispatcher.current.useTransition();
};
exports.version = "18.3.0-www-classic-ba07b7d4";
exports.version = "18.3.0-www-classic-9048e373";
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
"function" ===
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&
Expand Down
2 changes: 1 addition & 1 deletion compiled/facebook-www/React-profiling.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ exports.useSyncExternalStore = function (
exports.useTransition = function () {
return ReactCurrentDispatcher.current.useTransition();
};
exports.version = "18.3.0-www-modern-dc34ad0a";
exports.version = "18.3.0-www-modern-c75eccb5";
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
"function" ===
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&
Expand Down
83 changes: 64 additions & 19 deletions compiled/facebook-www/ReactART-dev.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ if (__DEV__) {
return self;
}

var ReactVersion = "18.3.0-www-classic-3c471167";
var ReactVersion = "18.3.0-www-classic-1172eaef";

var LegacyRoot = 0;
var ConcurrentRoot = 1;
Expand Down Expand Up @@ -9873,7 +9873,13 @@ if (__DEV__) {
} // useFormState actions run sequentially, because each action receives the
// previous state as an argument. We store pending actions on a queue.

function dispatchFormState(fiber, actionQueue, setState, payload) {
function dispatchFormState(
fiber,
actionQueue,
setPendingState,
setState,
payload
) {
if (isRenderPhaseUpdate(fiber)) {
throw new Error("Cannot update form state while rendering.");
}
Expand All @@ -9888,7 +9894,7 @@ if (__DEV__) {
next: null // circular
};
newLast.next = actionQueue.pending = newLast;
runFormStateAction(actionQueue, setState, payload);
runFormStateAction(actionQueue, setPendingState, setState, payload);
} else {
// There's already an action running. Add to the queue.
var first = last.next;
Expand All @@ -9900,7 +9906,12 @@ if (__DEV__) {
}
}

function runFormStateAction(actionQueue, setState, payload) {
function runFormStateAction(
actionQueue,
setPendingState,
setState,
payload
) {
var action = actionQueue.action;
var prevState = actionQueue.state; // This is a fork of startTransition

Expand All @@ -9912,7 +9923,10 @@ if (__DEV__) {

{
ReactCurrentBatchConfig$2.transition._updatedFibers = new Set();
}
} // Optimistically update the pending state, similar to useTransition.
// This will be reverted automatically when all actions are finished.

setPendingState(true);

try {
var returnValue = action(prevState, payload);
Expand All @@ -9929,18 +9943,26 @@ if (__DEV__) {
thenable.then(
function (nextState) {
actionQueue.state = nextState;
finishRunningFormStateAction(actionQueue, setState);
finishRunningFormStateAction(
actionQueue,
setPendingState,
setState
);
},
function () {
return finishRunningFormStateAction(actionQueue, setState);
return finishRunningFormStateAction(
actionQueue,
setPendingState,
setState
);
}
);
setState(thenable);
} else {
setState(returnValue);
var nextState = returnValue;
actionQueue.state = nextState;
finishRunningFormStateAction(actionQueue, setState);
finishRunningFormStateAction(actionQueue, setPendingState, setState);
}
} catch (error) {
// This is a trick to get the `useFormState` hook to rethrow the error.
Expand All @@ -9952,7 +9974,7 @@ if (__DEV__) {
reason: error // $FlowFixMe: Not sure why this doesn't work
};
setState(rejectedThenable);
finishRunningFormStateAction(actionQueue, setState);
finishRunningFormStateAction(actionQueue, setPendingState, setState);
} finally {
ReactCurrentBatchConfig$2.transition = prevTransition;

Expand All @@ -9974,7 +9996,11 @@ if (__DEV__) {
}
}

function finishRunningFormStateAction(actionQueue, setState) {
function finishRunningFormStateAction(
actionQueue,
setPendingState,
setState
) {
// The action finished running. Pop it from the queue and run the next pending
// action, if there are any.
var last = actionQueue.pending;
Expand All @@ -9990,7 +10016,12 @@ if (__DEV__) {
var next = first.next;
last.next = next; // Run the next action.

runFormStateAction(actionQueue, setState, next.payload);
runFormStateAction(
actionQueue,
setPendingState,
setState,
next.payload
);
}
}
}
Expand Down Expand Up @@ -10020,7 +10051,16 @@ if (__DEV__) {
currentlyRenderingFiber$1,
stateQueue
);
stateQueue.dispatch = setState; // Action queue hook. This is used to queue pending actions. The queue is
stateQueue.dispatch = setState; // Pending state. This is used to store the pending state of the action.
// Tracked optimistically, like a transition pending state.

var pendingStateHook = mountStateImpl(false);
var setPendingState = dispatchOptimisticSetState.bind(
null,
currentlyRenderingFiber$1,
false,
pendingStateHook.queue
); // Action queue hook. This is used to queue pending actions. The queue is
// shared between all instances of the hook. Similar to a regular state queue,
// but different because the actions are run sequentially, and they run in
// an event instead of during render.
Expand All @@ -10038,14 +10078,15 @@ if (__DEV__) {
null,
currentlyRenderingFiber$1,
actionQueue,
setPendingState,
setState
);
actionQueue.dispatch = dispatch; // Stash the action function on the memoized state of the hook. We'll use this
// to detect when the action function changes so we can update it in
// an effect.

actionQueueHook.memoizedState = action;
return [initialState, dispatch];
return [initialState, dispatch, false];
}

function updateFormState(action, initialState, permalink) {
Expand All @@ -10066,7 +10107,10 @@ if (__DEV__) {
currentStateHook,
formStateReducer
),
actionResult = _updateReducerImpl[0]; // This will suspend until the action finishes.
actionResult = _updateReducerImpl[0];

var _updateState = updateState(),
isPending = _updateState[0]; // This will suspend until the action finishes.

var state =
typeof actionResult === "object" &&
Expand All @@ -10090,7 +10134,7 @@ if (__DEV__) {
);
}

return [state, dispatch];
return [state, dispatch, isPending];
}

function formStateActionEffect(actionQueue, action) {
Expand Down Expand Up @@ -10118,8 +10162,9 @@ if (__DEV__) {
var actionQueue = actionQueueHook.queue;
var dispatch = actionQueue.dispatch; // This may have changed during the rerender.

actionQueueHook.memoizedState = action;
return [state, dispatch];
actionQueueHook.memoizedState = action; // For mount, pending is always false.

return [state, dispatch, false];
}

function pushEffect(tag, create, inst, deps) {
Expand Down Expand Up @@ -10758,8 +10803,8 @@ if (__DEV__) {
}

function updateTransition() {
var _updateState = updateState(),
booleanOrThenable = _updateState[0];
var _updateState2 = updateState(),
booleanOrThenable = _updateState2[0];

var hook = updateWorkInProgressHook();
var start = hook.memoizedState;
Expand Down
Loading

0 comments on commit 8e12d48

Please sign in to comment.