Fix: useOptimistic should return passthrough value when there are no updates pending (#27936)

This fixes a bug that happened when the canonical value passed to
useOptimistic without an accompanying call to setOptimistic. In this
scenario, useOptimistic should pass through the new canonical value.

I had written tests for the more complicated scenario, where a new value
is passed while there are still pending optimistic updates, but not this
simpler one.

DiffTrain build for commit https://github.com/facebook/react/commit/60a927d04ad3888facebcdf7da620aa1cfc9528f.
This commit is contained in:
acdlite
2024-01-14 02:42:09 +00:00
parent cbb38c72ac
commit d2a2a66614
13 changed files with 117 additions and 84 deletions
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<fc408c74cd117076cbc05c2d9747b81d>>
* @generated SignedSource<<c2d754b18a9eb7cb4c4c644819a4d828>>
*/
"use strict";
@@ -7685,10 +7685,19 @@ if (__DEV__) {
queue.pending = null;
}
if (baseQueue !== null) {
var baseState = hook.baseState;
if (baseQueue === null) {
// If there are no pending updates, then the memoized state should be the
// same as the base state. Currently these only diverge in the case of
// useOptimistic, because useOptimistic accepts a new baseState on
// every render.
hook.memoizedState = baseState; // We don't need to call markWorkInProgressReceivedUpdate because
// baseState is derived from other reactive values.
} else {
// We have a queue to process.
var first = baseQueue.next;
var newState = hook.baseState;
var newState = baseState;
var newBaseState = null;
var newBaseQueueFirst = null;
var newBaseQueueLast = null;
@@ -25531,7 +25540,7 @@ if (__DEV__) {
return root;
}
var ReactVersion = "18.3.0-canary-33068c9db-20240112";
var ReactVersion = "18.3.0-canary-60a927d04-20240113";
// Might add PROFILE later.
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<09dbf4f778ca917e96108791bdd4cd8e>>
* @generated SignedSource<<d07c017ce198fa80983d34f3c3d63dda>>
*/
"use strict";
@@ -2531,9 +2531,10 @@ function updateReducerImpl(hook, current, reducer) {
current.baseQueue = baseQueue = pendingQueue;
queue.pending = null;
}
if (null !== baseQueue) {
pendingQueue = hook.baseState;
if (null === baseQueue) hook.memoizedState = pendingQueue;
else {
current = baseQueue.next;
pendingQueue = hook.baseState;
var newBaseQueueFirst = (baseFirst = null),
newBaseQueueLast = null,
update = current;
@@ -9121,7 +9122,7 @@ var devToolsConfig$jscomp$inline_1037 = {
throw Error("TestRenderer does not support findFiberByHostInstance()");
},
bundleType: 0,
version: "18.3.0-canary-33068c9db-20240112",
version: "18.3.0-canary-60a927d04-20240113",
rendererPackageName: "react-test-renderer"
};
var internals$jscomp$inline_1230 = {
@@ -9152,7 +9153,7 @@ var internals$jscomp$inline_1230 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-canary-33068c9db-20240112"
reconcilerVersion: "18.3.0-canary-60a927d04-20240113"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_1231 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<7b9b447b7ed58bc7f344d3fd301db92f>>
* @generated SignedSource<<cc5b4b4d4992af1878302a2a335f8e0a>>
*/
"use strict";
@@ -2551,9 +2551,10 @@ function updateReducerImpl(hook, current, reducer) {
current.baseQueue = baseQueue = pendingQueue;
queue.pending = null;
}
if (null !== baseQueue) {
pendingQueue = hook.baseState;
if (null === baseQueue) hook.memoizedState = pendingQueue;
else {
current = baseQueue.next;
pendingQueue = hook.baseState;
var newBaseQueueFirst = (baseFirst = null),
newBaseQueueLast = null,
update = current;
@@ -9549,7 +9550,7 @@ var devToolsConfig$jscomp$inline_1079 = {
throw Error("TestRenderer does not support findFiberByHostInstance()");
},
bundleType: 0,
version: "18.3.0-canary-33068c9db-20240112",
version: "18.3.0-canary-60a927d04-20240113",
rendererPackageName: "react-test-renderer"
};
var internals$jscomp$inline_1271 = {
@@ -9580,7 +9581,7 @@ var internals$jscomp$inline_1271 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-canary-33068c9db-20240112"
reconcilerVersion: "18.3.0-canary-60a927d04-20240113"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_1272 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -24,7 +24,7 @@ if (__DEV__) {
) {
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error());
}
var ReactVersion = "18.3.0-canary-33068c9db-20240112";
var ReactVersion = "18.3.0-canary-60a927d04-20240113";
// ATTENTION
// When adding new symbols to this file,
@@ -580,4 +580,4 @@ exports.useSyncExternalStore = function (
exports.useTransition = function () {
return ReactCurrentDispatcher.current.useTransition();
};
exports.version = "18.3.0-canary-33068c9db-20240112";
exports.version = "18.3.0-canary-60a927d04-20240113";
@@ -576,7 +576,7 @@ exports.useSyncExternalStore = function (
exports.useTransition = function () {
return ReactCurrentDispatcher.current.useTransition();
};
exports.version = "18.3.0-canary-33068c9db-20240112";
exports.version = "18.3.0-canary-60a927d04-20240113";
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
"function" ===
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&
@@ -1 +1 @@
33068c9db9153a479bb29d138397cb9c32fabfdd
60a927d04ad3888facebcdf7da620aa1cfc9528f
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<8093e023e848964848b2e08a5762599f>>
* @generated SignedSource<<3bbc5516aa8fca4c50bd6b2679dc8923>>
*/
"use strict";
@@ -11498,10 +11498,19 @@ to return true:wantsResponderID| |
queue.pending = null;
}
if (baseQueue !== null) {
var baseState = hook.baseState;
if (baseQueue === null) {
// If there are no pending updates, then the memoized state should be the
// same as the base state. Currently these only diverge in the case of
// useOptimistic, because useOptimistic accepts a new baseState on
// every render.
hook.memoizedState = baseState; // We don't need to call markWorkInProgressReceivedUpdate because
// baseState is derived from other reactive values.
} else {
// We have a queue to process.
var first = baseQueue.next;
var newState = hook.baseState;
var newState = baseState;
var newBaseState = null;
var newBaseQueueFirst = null;
var newBaseQueueLast = null;
@@ -27829,7 +27838,7 @@ to return true:wantsResponderID| |
return root;
}
var ReactVersion = "18.3.0-canary-247f0e0d";
var ReactVersion = "18.3.0-canary-58de2f66";
function createPortal$1(
children,
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<f143c1c3879cd2bea8f0434af516bbbf>>
* @generated SignedSource<<6e407622da5495d67c0b1b946f5635a4>>
*/
"use strict";
@@ -3814,9 +3814,10 @@ function updateReducer(reducer) {
current.baseQueue = baseQueue = pendingQueue;
queue.pending = null;
}
if (null !== baseQueue) {
pendingQueue = hook.baseState;
if (null === baseQueue) hook.memoizedState = pendingQueue;
else {
current = baseQueue.next;
pendingQueue = hook.baseState;
var newBaseQueueFirst = (baseFirst = null),
newBaseQueueLast = null,
update = current;
@@ -9549,10 +9550,10 @@ batchedUpdatesImpl = function (fn, a) {
}
};
var roots = new Map(),
devToolsConfig$jscomp$inline_1053 = {
devToolsConfig$jscomp$inline_1054 = {
findFiberByHostInstance: getInstanceFromNode,
bundleType: 0,
version: "18.3.0-canary-e5b06734",
version: "18.3.0-canary-4aee1a03",
rendererPackageName: "react-native-renderer",
rendererConfig: {
getInspectorDataForInstance: getInspectorDataForInstance,
@@ -9568,11 +9569,11 @@ var roots = new Map(),
}.bind(null, findNodeHandle)
}
};
var internals$jscomp$inline_1292 = {
bundleType: devToolsConfig$jscomp$inline_1053.bundleType,
version: devToolsConfig$jscomp$inline_1053.version,
rendererPackageName: devToolsConfig$jscomp$inline_1053.rendererPackageName,
rendererConfig: devToolsConfig$jscomp$inline_1053.rendererConfig,
var internals$jscomp$inline_1293 = {
bundleType: devToolsConfig$jscomp$inline_1054.bundleType,
version: devToolsConfig$jscomp$inline_1054.version,
rendererPackageName: devToolsConfig$jscomp$inline_1054.rendererPackageName,
rendererConfig: devToolsConfig$jscomp$inline_1054.rendererConfig,
overrideHookState: null,
overrideHookStateDeletePath: null,
overrideHookStateRenamePath: null,
@@ -9588,26 +9589,26 @@ var internals$jscomp$inline_1292 = {
return null === fiber ? null : fiber.stateNode;
},
findFiberByHostInstance:
devToolsConfig$jscomp$inline_1053.findFiberByHostInstance ||
devToolsConfig$jscomp$inline_1054.findFiberByHostInstance ||
emptyFindFiberByHostInstance,
findHostInstancesForRefresh: null,
scheduleRefresh: null,
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-canary-e5b06734"
reconcilerVersion: "18.3.0-canary-4aee1a03"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_1293 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
var hook$jscomp$inline_1294 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
if (
!hook$jscomp$inline_1293.isDisabled &&
hook$jscomp$inline_1293.supportsFiber
!hook$jscomp$inline_1294.isDisabled &&
hook$jscomp$inline_1294.supportsFiber
)
try {
(rendererID = hook$jscomp$inline_1293.inject(
internals$jscomp$inline_1292
(rendererID = hook$jscomp$inline_1294.inject(
internals$jscomp$inline_1293
)),
(injectedHook = hook$jscomp$inline_1293);
(injectedHook = hook$jscomp$inline_1294);
} catch (err) {}
}
exports.createPortal = function (children, containerTag) {
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<2607cd5e41323c146ac09ecbb5682ce5>>
* @generated SignedSource<<e63c28c66e569a08046155e4355e34c0>>
*/
"use strict";
@@ -3938,9 +3938,10 @@ function updateReducer(reducer) {
current.baseQueue = baseQueue = pendingQueue;
queue.pending = null;
}
if (null !== baseQueue) {
pendingQueue = hook.baseState;
if (null === baseQueue) hook.memoizedState = pendingQueue;
else {
current = baseQueue.next;
pendingQueue = hook.baseState;
var newBaseQueueFirst = (baseFirst = null),
newBaseQueueLast = null,
update = current;
@@ -10251,10 +10252,10 @@ batchedUpdatesImpl = function (fn, a) {
}
};
var roots = new Map(),
devToolsConfig$jscomp$inline_1131 = {
devToolsConfig$jscomp$inline_1132 = {
findFiberByHostInstance: getInstanceFromNode,
bundleType: 0,
version: "18.3.0-canary-1b36a89c",
version: "18.3.0-canary-575afa21",
rendererPackageName: "react-native-renderer",
rendererConfig: {
getInspectorDataForInstance: getInspectorDataForInstance,
@@ -10284,10 +10285,10 @@ var roots = new Map(),
} catch (err) {}
return hook.checkDCE ? !0 : !1;
})({
bundleType: devToolsConfig$jscomp$inline_1131.bundleType,
version: devToolsConfig$jscomp$inline_1131.version,
rendererPackageName: devToolsConfig$jscomp$inline_1131.rendererPackageName,
rendererConfig: devToolsConfig$jscomp$inline_1131.rendererConfig,
bundleType: devToolsConfig$jscomp$inline_1132.bundleType,
version: devToolsConfig$jscomp$inline_1132.version,
rendererPackageName: devToolsConfig$jscomp$inline_1132.rendererPackageName,
rendererConfig: devToolsConfig$jscomp$inline_1132.rendererConfig,
overrideHookState: null,
overrideHookStateDeletePath: null,
overrideHookStateRenamePath: null,
@@ -10303,14 +10304,14 @@ var roots = new Map(),
return null === fiber ? null : fiber.stateNode;
},
findFiberByHostInstance:
devToolsConfig$jscomp$inline_1131.findFiberByHostInstance ||
devToolsConfig$jscomp$inline_1132.findFiberByHostInstance ||
emptyFindFiberByHostInstance,
findHostInstancesForRefresh: null,
scheduleRefresh: null,
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-canary-1b36a89c"
reconcilerVersion: "18.3.0-canary-575afa21"
});
exports.createPortal = function (children, containerTag) {
return createPortal$1(
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<1c328ab6e9e5cacb27445a075ae945c2>>
* @generated SignedSource<<7117023f3b40093a08a4623516c9c86b>>
*/
"use strict";
@@ -11770,10 +11770,19 @@ to return true:wantsResponderID| |
queue.pending = null;
}
if (baseQueue !== null) {
var baseState = hook.baseState;
if (baseQueue === null) {
// If there are no pending updates, then the memoized state should be the
// same as the base state. Currently these only diverge in the case of
// useOptimistic, because useOptimistic accepts a new baseState on
// every render.
hook.memoizedState = baseState; // We don't need to call markWorkInProgressReceivedUpdate because
// baseState is derived from other reactive values.
} else {
// We have a queue to process.
var first = baseQueue.next;
var newState = hook.baseState;
var newState = baseState;
var newBaseState = null;
var newBaseQueueFirst = null;
var newBaseQueueLast = null;
@@ -28270,7 +28279,7 @@ to return true:wantsResponderID| |
return root;
}
var ReactVersion = "18.3.0-canary-5c402d39";
var ReactVersion = "18.3.0-canary-e2b49fad";
function createPortal$1(
children,
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<78e8bb7a2adc886af3ab9b693ce4f7cd>>
* @generated SignedSource<<f387fd3e5912def13cb382c916b29778>>
*/
"use strict";
@@ -3890,9 +3890,10 @@ function updateReducer(reducer) {
current.baseQueue = baseQueue = pendingQueue;
queue.pending = null;
}
if (null !== baseQueue) {
pendingQueue = hook.baseState;
if (null === baseQueue) hook.memoizedState = pendingQueue;
else {
current = baseQueue.next;
pendingQueue = hook.baseState;
var newBaseQueueFirst = (baseFirst = null),
newBaseQueueLast = null,
update = current;
@@ -9771,10 +9772,10 @@ batchedUpdatesImpl = function (fn, a) {
}
};
var roots = new Map(),
devToolsConfig$jscomp$inline_1116 = {
devToolsConfig$jscomp$inline_1117 = {
findFiberByHostInstance: getInstanceFromTag,
bundleType: 0,
version: "18.3.0-canary-70aaf409",
version: "18.3.0-canary-d76fd1b4",
rendererPackageName: "react-native-renderer",
rendererConfig: {
getInspectorDataForInstance: getInspectorDataForInstance,
@@ -9790,11 +9791,11 @@ var roots = new Map(),
}.bind(null, findNodeHandle)
}
};
var internals$jscomp$inline_1369 = {
bundleType: devToolsConfig$jscomp$inline_1116.bundleType,
version: devToolsConfig$jscomp$inline_1116.version,
rendererPackageName: devToolsConfig$jscomp$inline_1116.rendererPackageName,
rendererConfig: devToolsConfig$jscomp$inline_1116.rendererConfig,
var internals$jscomp$inline_1370 = {
bundleType: devToolsConfig$jscomp$inline_1117.bundleType,
version: devToolsConfig$jscomp$inline_1117.version,
rendererPackageName: devToolsConfig$jscomp$inline_1117.rendererPackageName,
rendererConfig: devToolsConfig$jscomp$inline_1117.rendererConfig,
overrideHookState: null,
overrideHookStateDeletePath: null,
overrideHookStateRenamePath: null,
@@ -9810,26 +9811,26 @@ var internals$jscomp$inline_1369 = {
return null === fiber ? null : fiber.stateNode;
},
findFiberByHostInstance:
devToolsConfig$jscomp$inline_1116.findFiberByHostInstance ||
devToolsConfig$jscomp$inline_1117.findFiberByHostInstance ||
emptyFindFiberByHostInstance,
findHostInstancesForRefresh: null,
scheduleRefresh: null,
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-canary-70aaf409"
reconcilerVersion: "18.3.0-canary-d76fd1b4"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_1370 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
var hook$jscomp$inline_1371 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
if (
!hook$jscomp$inline_1370.isDisabled &&
hook$jscomp$inline_1370.supportsFiber
!hook$jscomp$inline_1371.isDisabled &&
hook$jscomp$inline_1371.supportsFiber
)
try {
(rendererID = hook$jscomp$inline_1370.inject(
internals$jscomp$inline_1369
(rendererID = hook$jscomp$inline_1371.inject(
internals$jscomp$inline_1370
)),
(injectedHook = hook$jscomp$inline_1370);
(injectedHook = hook$jscomp$inline_1371);
} catch (err) {}
}
exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = {
@@ -7,7 +7,7 @@
* @noflow
* @nolint
* @preventMunge
* @generated SignedSource<<52366b4580e0960513a2a83f552181c8>>
* @generated SignedSource<<1ec259d95fb167ed4c8dd8c6c54e4cee>>
*/
"use strict";
@@ -4014,9 +4014,10 @@ function updateReducer(reducer) {
current.baseQueue = baseQueue = pendingQueue;
queue.pending = null;
}
if (null !== baseQueue) {
pendingQueue = hook.baseState;
if (null === baseQueue) hook.memoizedState = pendingQueue;
else {
current = baseQueue.next;
pendingQueue = hook.baseState;
var newBaseQueueFirst = (baseFirst = null),
newBaseQueueLast = null,
update = current;
@@ -10473,10 +10474,10 @@ batchedUpdatesImpl = function (fn, a) {
}
};
var roots = new Map(),
devToolsConfig$jscomp$inline_1194 = {
devToolsConfig$jscomp$inline_1195 = {
findFiberByHostInstance: getInstanceFromTag,
bundleType: 0,
version: "18.3.0-canary-0210e876",
version: "18.3.0-canary-f4e963ab",
rendererPackageName: "react-native-renderer",
rendererConfig: {
getInspectorDataForInstance: getInspectorDataForInstance,
@@ -10506,10 +10507,10 @@ var roots = new Map(),
} catch (err) {}
return hook.checkDCE ? !0 : !1;
})({
bundleType: devToolsConfig$jscomp$inline_1194.bundleType,
version: devToolsConfig$jscomp$inline_1194.version,
rendererPackageName: devToolsConfig$jscomp$inline_1194.rendererPackageName,
rendererConfig: devToolsConfig$jscomp$inline_1194.rendererConfig,
bundleType: devToolsConfig$jscomp$inline_1195.bundleType,
version: devToolsConfig$jscomp$inline_1195.version,
rendererPackageName: devToolsConfig$jscomp$inline_1195.rendererPackageName,
rendererConfig: devToolsConfig$jscomp$inline_1195.rendererConfig,
overrideHookState: null,
overrideHookStateDeletePath: null,
overrideHookStateRenamePath: null,
@@ -10525,14 +10526,14 @@ var roots = new Map(),
return null === fiber ? null : fiber.stateNode;
},
findFiberByHostInstance:
devToolsConfig$jscomp$inline_1194.findFiberByHostInstance ||
devToolsConfig$jscomp$inline_1195.findFiberByHostInstance ||
emptyFindFiberByHostInstance,
findHostInstancesForRefresh: null,
scheduleRefresh: null,
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-canary-0210e876"
reconcilerVersion: "18.3.0-canary-f4e963ab"
});
exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = {
computeComponentStackForErrorReporting: function (reactTag) {