Skip to content

Commit

Permalink
Fix: Use action implementation at time of dispatch (#29618)
Browse files Browse the repository at this point in the history
Fixes the behavior of actions that are queued by useActionState to use
the action function that was current at the time it was dispatched, not
at the time it eventually executes.

The conceptual model is that the action is immediately dispatched, as if
it were sent to a remote server/worker. It's the remote worker that
maintains the queue, not the client.

This is another property of actions makes them more like event handlers
than like reducers.

DiffTrain build for [1631227](1631227)
  • Loading branch information
acdlite committed May 28, 2024
1 parent 0af082e commit e5c63ba
Show file tree
Hide file tree
Showing 21 changed files with 315 additions and 267 deletions.
2 changes: 1 addition & 1 deletion compiled/facebook-www/REVISION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2787eebe52864356252a280fd811cd9d52807a82
163122766b6008e992898b00f1fe3b104ed78737
25 changes: 17 additions & 8 deletions compiled/facebook-www/ReactART-dev.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function _assertThisInitialized(self) {
return self;
}

var ReactVersion = '19.0.0-www-classic-1c397ec5';
var ReactVersion = '19.0.0-www-classic-15a88fe3';

var LegacyRoot = 0;
var ConcurrentRoot = 1;
Expand Down Expand Up @@ -9255,26 +9255,26 @@ function dispatchActionState(fiber, actionQueue, setPendingState, setState, payl
// it immediately.
var newLast = {
payload: payload,
action: actionQueue.action,
next: null // circular

};
newLast.next = actionQueue.pending = newLast;
runActionStateAction(actionQueue, setPendingState, setState, payload);
runActionStateAction(actionQueue, setPendingState, setState, newLast);
} else {
// There's already an action running. Add to the queue.
var first = last.next;
var _newLast = {
payload: payload,
action: actionQueue.action,
next: first
};
actionQueue.pending = last.next = _newLast;
}
}

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

function runActionStateAction(actionQueue, setPendingState, setState, node) {
// This is a fork of startTransition
var prevTransition = ReactSharedInternals.T;
var currentTransition = {};
ReactSharedInternals.T = currentTransition;
Expand All @@ -9285,7 +9285,16 @@ function runActionStateAction(actionQueue, setPendingState, setState, payload) {
// This will be reverted automatically when all actions are finished.


setPendingState(true);
setPendingState(true); // `node.action` represents the action function at the time it was dispatched.
// If this action was queued, it might be stale, i.e. it's not necessarily the
// most current implementation of the action, stored on `actionQueue`. This is
// intentional. The conceptual model for queued actions is that they are
// queued in a remote worker; the dispatch happens immediately, only the
// execution is delayed.

var action = node.action;
var payload = node.payload;
var prevState = actionQueue.state;

try {
var returnValue = action(prevState, payload);
Expand Down Expand Up @@ -9358,7 +9367,7 @@ function finishRunningActionStateAction(actionQueue, setPendingState, setState)
var next = first.next;
last.next = next; // Run the next action.

runActionStateAction(actionQueue, setPendingState, setState, next.payload);
runActionStateAction(actionQueue, setPendingState, setState, next);
}
}
}
Expand Down
25 changes: 17 additions & 8 deletions compiled/facebook-www/ReactART-dev.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function _assertThisInitialized(self) {
return self;
}

var ReactVersion = '19.0.0-www-modern-67a1f020';
var ReactVersion = '19.0.0-www-modern-3e83ee0c';

var LegacyRoot = 0;
var ConcurrentRoot = 1;
Expand Down Expand Up @@ -9044,26 +9044,26 @@ function dispatchActionState(fiber, actionQueue, setPendingState, setState, payl
// it immediately.
var newLast = {
payload: payload,
action: actionQueue.action,
next: null // circular

};
newLast.next = actionQueue.pending = newLast;
runActionStateAction(actionQueue, setPendingState, setState, payload);
runActionStateAction(actionQueue, setPendingState, setState, newLast);
} else {
// There's already an action running. Add to the queue.
var first = last.next;
var _newLast = {
payload: payload,
action: actionQueue.action,
next: first
};
actionQueue.pending = last.next = _newLast;
}
}

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

function runActionStateAction(actionQueue, setPendingState, setState, node) {
// This is a fork of startTransition
var prevTransition = ReactSharedInternals.T;
var currentTransition = {};
ReactSharedInternals.T = currentTransition;
Expand All @@ -9074,7 +9074,16 @@ function runActionStateAction(actionQueue, setPendingState, setState, payload) {
// This will be reverted automatically when all actions are finished.


setPendingState(true);
setPendingState(true); // `node.action` represents the action function at the time it was dispatched.
// If this action was queued, it might be stale, i.e. it's not necessarily the
// most current implementation of the action, stored on `actionQueue`. This is
// intentional. The conceptual model for queued actions is that they are
// queued in a remote worker; the dispatch happens immediately, only the
// execution is delayed.

var action = node.action;
var payload = node.payload;
var prevState = actionQueue.state;

try {
var returnValue = action(prevState, payload);
Expand Down Expand Up @@ -9147,7 +9156,7 @@ function finishRunningActionStateAction(actionQueue, setPendingState, setState)
var next = first.next;
last.next = next; // Run the next action.

runActionStateAction(actionQueue, setPendingState, setState, next.payload);
runActionStateAction(actionQueue, setPendingState, setState, next);
}
}
}
Expand Down
28 changes: 12 additions & 16 deletions compiled/facebook-www/ReactART-prod.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -3015,21 +3015,22 @@ function dispatchActionState(
if (isRenderPhaseUpdate(fiber)) throw Error(formatProdErrorMessage(485));
fiber = actionQueue.pending;
null === fiber
? ((fiber = { payload: payload, next: null }),
(fiber.next = actionQueue.pending = fiber),
? ((payload = { payload: payload, action: actionQueue.action, next: null }),
(payload.next = actionQueue.pending = payload),
runActionStateAction(actionQueue, setPendingState, setState, payload))
: (actionQueue.pending = fiber.next =
{ payload: payload, next: fiber.next });
{ payload: payload, action: actionQueue.action, next: fiber.next });
}
function runActionStateAction(actionQueue, setPendingState, setState, payload) {
var action = actionQueue.action,
prevState = actionQueue.state,
prevTransition = ReactSharedInternals.T,
function runActionStateAction(actionQueue, setPendingState, setState, node) {
var prevTransition = ReactSharedInternals.T,
currentTransition = {};
ReactSharedInternals.T = currentTransition;
setPendingState(!0);
var action = node.action;
node = node.payload;
var prevState = actionQueue.state;
try {
var returnValue = action(prevState, payload),
var returnValue = action(prevState, node),
onStartTransitionFinish = ReactSharedInternals.S;
null !== onStartTransitionFinish &&
onStartTransitionFinish(currentTransition, returnValue);
Expand Down Expand Up @@ -3076,12 +3077,7 @@ function finishRunningActionStateAction(
? (actionQueue.pending = null)
: ((first = first.next),
(last.next = first),
runActionStateAction(
actionQueue,
setPendingState,
setState,
first.payload
));
runActionStateAction(actionQueue, setPendingState, setState, first));
}
}
function actionStateReducer(oldState, newState) {
Expand Down Expand Up @@ -10644,7 +10640,7 @@ var slice = Array.prototype.slice,
return null;
},
bundleType: 0,
version: "19.0.0-www-classic-720dabbc",
version: "19.0.0-www-classic-12951007",
rendererPackageName: "react-art"
};
var internals$jscomp$inline_1370 = {
Expand Down Expand Up @@ -10675,7 +10671,7 @@ var internals$jscomp$inline_1370 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "19.0.0-www-classic-720dabbc"
reconcilerVersion: "19.0.0-www-classic-12951007"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_1371 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
Expand Down
28 changes: 12 additions & 16 deletions compiled/facebook-www/ReactART-prod.modern.js
Original file line number Diff line number Diff line change
Expand Up @@ -2813,21 +2813,22 @@ function dispatchActionState(
if (isRenderPhaseUpdate(fiber)) throw Error(formatProdErrorMessage(485));
fiber = actionQueue.pending;
null === fiber
? ((fiber = { payload: payload, next: null }),
(fiber.next = actionQueue.pending = fiber),
? ((payload = { payload: payload, action: actionQueue.action, next: null }),
(payload.next = actionQueue.pending = payload),
runActionStateAction(actionQueue, setPendingState, setState, payload))
: (actionQueue.pending = fiber.next =
{ payload: payload, next: fiber.next });
{ payload: payload, action: actionQueue.action, next: fiber.next });
}
function runActionStateAction(actionQueue, setPendingState, setState, payload) {
var action = actionQueue.action,
prevState = actionQueue.state,
prevTransition = ReactSharedInternals.T,
function runActionStateAction(actionQueue, setPendingState, setState, node) {
var prevTransition = ReactSharedInternals.T,
currentTransition = {};
ReactSharedInternals.T = currentTransition;
setPendingState(!0);
var action = node.action;
node = node.payload;
var prevState = actionQueue.state;
try {
var returnValue = action(prevState, payload),
var returnValue = action(prevState, node),
onStartTransitionFinish = ReactSharedInternals.S;
null !== onStartTransitionFinish &&
onStartTransitionFinish(currentTransition, returnValue);
Expand Down Expand Up @@ -2874,12 +2875,7 @@ function finishRunningActionStateAction(
? (actionQueue.pending = null)
: ((first = first.next),
(last.next = first),
runActionStateAction(
actionQueue,
setPendingState,
setState,
first.payload
));
runActionStateAction(actionQueue, setPendingState, setState, first));
}
}
function actionStateReducer(oldState, newState) {
Expand Down Expand Up @@ -10119,7 +10115,7 @@ var slice = Array.prototype.slice,
return null;
},
bundleType: 0,
version: "19.0.0-www-modern-bfe50115",
version: "19.0.0-www-modern-fc3d605e",
rendererPackageName: "react-art"
};
var internals$jscomp$inline_1356 = {
Expand Down Expand Up @@ -10150,7 +10146,7 @@ var internals$jscomp$inline_1356 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "19.0.0-www-modern-bfe50115"
reconcilerVersion: "19.0.0-www-modern-fc3d605e"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_1357 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
Expand Down
25 changes: 17 additions & 8 deletions compiled/facebook-www/ReactDOM-dev.classic.js
Original file line number Diff line number Diff line change
Expand Up @@ -12955,26 +12955,26 @@ function dispatchActionState(fiber, actionQueue, setPendingState, setState, payl
// it immediately.
var newLast = {
payload: payload,
action: actionQueue.action,
next: null // circular

};
newLast.next = actionQueue.pending = newLast;
runActionStateAction(actionQueue, setPendingState, setState, payload);
runActionStateAction(actionQueue, setPendingState, setState, newLast);
} else {
// There's already an action running. Add to the queue.
var first = last.next;
var _newLast = {
payload: payload,
action: actionQueue.action,
next: first
};
actionQueue.pending = last.next = _newLast;
}
}

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

function runActionStateAction(actionQueue, setPendingState, setState, node) {
// This is a fork of startTransition
var prevTransition = ReactSharedInternals.T;
var currentTransition = {};
ReactSharedInternals.T = currentTransition;
Expand All @@ -12985,7 +12985,16 @@ function runActionStateAction(actionQueue, setPendingState, setState, payload) {
// This will be reverted automatically when all actions are finished.


setPendingState(true);
setPendingState(true); // `node.action` represents the action function at the time it was dispatched.
// If this action was queued, it might be stale, i.e. it's not necessarily the
// most current implementation of the action, stored on `actionQueue`. This is
// intentional. The conceptual model for queued actions is that they are
// queued in a remote worker; the dispatch happens immediately, only the
// execution is delayed.

var action = node.action;
var payload = node.payload;
var prevState = actionQueue.state;

try {
var returnValue = action(prevState, payload);
Expand Down Expand Up @@ -13058,7 +13067,7 @@ function finishRunningActionStateAction(actionQueue, setPendingState, setState)
var next = first.next;
last.next = next; // Run the next action.

runActionStateAction(actionQueue, setPendingState, setState, next.payload);
runActionStateAction(actionQueue, setPendingState, setState, next);
}
}
}
Expand Down Expand Up @@ -31050,7 +31059,7 @@ identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, transition
return root;
}

var ReactVersion = '19.0.0-www-classic-5c643ca1';
var ReactVersion = '19.0.0-www-classic-8bd79cb3';

function createPortal$1(children, containerInfo, // TODO: figure out the API for cross-renderer implementation.
implementation) {
Expand Down
Loading

0 comments on commit e5c63ba

Please sign in to comment.