Skip to content

Commit 1050447

Browse files
committed
Prerendering support for useDeferredValue (#27512)
### Based on #27509 Revealing a prerendered tree (hidden -> visible) is considered the same as mounting a brand new tree. So, when an initialValue argument is passed to useDeferredValue, and it's prerendered inside a hidden tree, we should first prerender the initial value. After the initial value has been prerendered, we switch to prerendering the final one. This is the same sequence that we use when mounting new visible tree. Depending on how much prerendering work has been finished by the time the tree is revealed, we may or may not be able to skip all the way to the final value. This means we get the benefits of both prerendering and preview states: if we have enough resources to prerender the whole thing, we do that. If we don't, we have a preview state to show for immediate feedback. DiffTrain build for [75c1bd7](75c1bd7)
1 parent 385a8f1 commit 1050447

23 files changed

+769
-697
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
b2a68a65c84b63ac86930d88ae5c84380cbbdeb6
1+
75c1bd7ee7e4a87a4dd0f560e157c57957ef823b

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-8c719f5e";
30+
var ReactVersion = "18.3.0-www-classic-08b720b1";
3131

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

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -587,4 +587,4 @@ exports.useSyncExternalStore = function (
587587
exports.useTransition = function () {
588588
return ReactCurrentDispatcher.current.useTransition();
589589
};
590-
exports.version = "18.3.0-www-classic-703d13e3";
590+
exports.version = "18.3.0-www-classic-a546ef8a";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,4 +579,4 @@ exports.useSyncExternalStore = function (
579579
exports.useTransition = function () {
580580
return ReactCurrentDispatcher.current.useTransition();
581581
};
582-
exports.version = "18.3.0-www-modern-eba2410d";
582+
exports.version = "18.3.0-www-modern-f25765d2";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ exports.useSyncExternalStore = function (
590590
exports.useTransition = function () {
591591
return ReactCurrentDispatcher.current.useTransition();
592592
};
593-
exports.version = "18.3.0-www-modern-f61d9097";
593+
exports.version = "18.3.0-www-modern-a1b21365";
594594

595595
/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
596596
if (

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

Lines changed: 40 additions & 42 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-8789cf1c";
72+
var ReactVersion = "18.3.0-www-classic-bb3a0070";
7373

7474
var LegacyRoot = 0;
7575
var ConcurrentRoot = 1;
@@ -9802,7 +9802,7 @@ function updateDeferredValue(value, initialValue) {
98029802
var hook = updateWorkInProgressHook();
98039803
var resolvedCurrentHook = currentHook;
98049804
var prevValue = resolvedCurrentHook.memoizedState;
9805-
return updateDeferredValueImpl(hook, prevValue, value);
9805+
return updateDeferredValueImpl(hook, prevValue, value, initialValue);
98069806
}
98079807

98089808
function rerenderDeferredValue(value, initialValue) {
@@ -9814,7 +9814,7 @@ function rerenderDeferredValue(value, initialValue) {
98149814
} else {
98159815
// This is a rerender during an update.
98169816
var prevValue = currentHook.memoizedState;
9817-
return updateDeferredValueImpl(hook, prevValue, value);
9817+
return updateDeferredValueImpl(hook, prevValue, value, initialValue);
98189818
}
98199819
}
98209820

@@ -9835,12 +9835,7 @@ function mountDeferredValueImpl(hook, value, initialValue) {
98359835
currentlyRenderingFiber$1.lanes,
98369836
deferredLane
98379837
);
9838-
markSkippedUpdateLanes(deferredLane); // Set this to true to indicate that the rendered value is inconsistent
9839-
// from the latest value. The name "baseState" doesn't really match how we
9840-
// use it because we're reusing a state hook field instead of creating a
9841-
// new one.
9842-
9843-
hook.baseState = true;
9838+
markSkippedUpdateLanes(deferredLane);
98449839
return initialValue;
98459840
} else {
98469841
hook.memoizedState = value;
@@ -9849,46 +9844,49 @@ function mountDeferredValueImpl(hook, value, initialValue) {
98499844
}
98509845

98519846
function updateDeferredValueImpl(hook, prevValue, value, initialValue) {
9852-
// TODO: We should also check if this component is going from
9853-
// hidden -> visible. If so, it should use the initialValue arg.
9854-
var shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes);
9855-
9856-
if (shouldDeferValue) {
9857-
// This is an urgent update. If the value has changed, keep using the
9858-
// previous value and spawn a deferred render to update it later.
9859-
if (!objectIs(value, prevValue)) {
9847+
if (objectIs(value, prevValue)) {
9848+
// The incoming value is referentially identical to the currently rendered
9849+
// value, so we can bail out quickly.
9850+
return value;
9851+
} else {
9852+
// Received a new value that's different from the current value.
9853+
// Check if we're inside a hidden tree
9854+
if (isCurrentTreeHidden()) {
9855+
// Revealing a prerendered tree is considered the same as mounting new
9856+
// one, so we reuse the "mount" path in this case.
9857+
var resultValue = mountDeferredValueImpl(hook, value, initialValue); // Unlike during an actual mount, we need to mark this as an update if
9858+
// the value changed.
9859+
9860+
if (!objectIs(resultValue, prevValue)) {
9861+
markWorkInProgressReceivedUpdate();
9862+
}
9863+
9864+
return resultValue;
9865+
}
9866+
9867+
var shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes);
9868+
9869+
if (shouldDeferValue) {
9870+
// This is an urgent update. Since the value has changed, keep using the
9871+
// previous value and spawn a deferred render to update it later.
98609872
// Schedule a deferred render
98619873
var deferredLane = requestDeferredLane();
98629874
currentlyRenderingFiber$1.lanes = mergeLanes(
98639875
currentlyRenderingFiber$1.lanes,
98649876
deferredLane
98659877
);
9866-
markSkippedUpdateLanes(deferredLane); // Set this to true to indicate that the rendered value is inconsistent
9867-
// from the latest value. The name "baseState" doesn't really match how we
9868-
// use it because we're reusing a state hook field instead of creating a
9869-
// new one.
9878+
markSkippedUpdateLanes(deferredLane); // Reuse the previous value. We do not need to mark this as an update,
9879+
// because we did not render a new value.
98709880

9871-
hook.baseState = true;
9872-
} // Reuse the previous value
9873-
9874-
return prevValue;
9875-
} else {
9876-
// This is not an urgent update, so we can use the latest value regardless
9877-
// of what it is. No need to defer it.
9878-
// However, if we're currently inside a spawned render, then we need to mark
9879-
// this as an update to prevent the fiber from bailing out.
9880-
//
9881-
// `baseState` is true when the current value is different from the rendered
9882-
// value. The name doesn't really match how we use it because we're reusing
9883-
// a state hook field instead of creating a new one.
9884-
if (hook.baseState) {
9885-
// Flip this back to false.
9886-
hook.baseState = false;
9881+
return prevValue;
9882+
} else {
9883+
// This is not an urgent update, so we can use the latest value regardless
9884+
// of what it is. No need to defer it.
9885+
// Mark this as an update to prevent the fiber from bailing out.
98879886
markWorkInProgressReceivedUpdate();
9887+
hook.memoizedState = value;
9888+
return value;
98889889
}
9889-
9890-
hook.memoizedState = value;
9891-
return value;
98929890
}
98939891
}
98949892

@@ -10825,7 +10823,7 @@ var InvalidNestedHooksDispatcherOnRerenderInDEV = null;
1082510823
useDeferredValue: function (value, initialValue) {
1082610824
currentHookNameInDev = "useDeferredValue";
1082710825
updateHookTypesDev();
10828-
return updateDeferredValue(value);
10826+
return updateDeferredValue(value, initialValue);
1082910827
},
1083010828
useTransition: function () {
1083110829
currentHookNameInDev = "useTransition";
@@ -11281,7 +11279,7 @@ var InvalidNestedHooksDispatcherOnRerenderInDEV = null;
1128111279
currentHookNameInDev = "useDeferredValue";
1128211280
warnInvalidHookAccess();
1128311281
updateHookTypesDev();
11284-
return updateDeferredValue(value);
11282+
return updateDeferredValue(value, initialValue);
1128511283
},
1128611284
useTransition: function () {
1128711285
currentHookNameInDev = "useTransition";

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

Lines changed: 40 additions & 42 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-bbf5dd10";
72+
var ReactVersion = "18.3.0-www-modern-f972e958";
7373

7474
var LegacyRoot = 0;
7575
var ConcurrentRoot = 1;
@@ -9558,7 +9558,7 @@ function updateDeferredValue(value, initialValue) {
95589558
var hook = updateWorkInProgressHook();
95599559
var resolvedCurrentHook = currentHook;
95609560
var prevValue = resolvedCurrentHook.memoizedState;
9561-
return updateDeferredValueImpl(hook, prevValue, value);
9561+
return updateDeferredValueImpl(hook, prevValue, value, initialValue);
95629562
}
95639563

95649564
function rerenderDeferredValue(value, initialValue) {
@@ -9570,7 +9570,7 @@ function rerenderDeferredValue(value, initialValue) {
95709570
} else {
95719571
// This is a rerender during an update.
95729572
var prevValue = currentHook.memoizedState;
9573-
return updateDeferredValueImpl(hook, prevValue, value);
9573+
return updateDeferredValueImpl(hook, prevValue, value, initialValue);
95749574
}
95759575
}
95769576

@@ -9591,12 +9591,7 @@ function mountDeferredValueImpl(hook, value, initialValue) {
95919591
currentlyRenderingFiber$1.lanes,
95929592
deferredLane
95939593
);
9594-
markSkippedUpdateLanes(deferredLane); // Set this to true to indicate that the rendered value is inconsistent
9595-
// from the latest value. The name "baseState" doesn't really match how we
9596-
// use it because we're reusing a state hook field instead of creating a
9597-
// new one.
9598-
9599-
hook.baseState = true;
9594+
markSkippedUpdateLanes(deferredLane);
96009595
return initialValue;
96019596
} else {
96029597
hook.memoizedState = value;
@@ -9605,46 +9600,49 @@ function mountDeferredValueImpl(hook, value, initialValue) {
96059600
}
96069601

96079602
function updateDeferredValueImpl(hook, prevValue, value, initialValue) {
9608-
// TODO: We should also check if this component is going from
9609-
// hidden -> visible. If so, it should use the initialValue arg.
9610-
var shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes);
9611-
9612-
if (shouldDeferValue) {
9613-
// This is an urgent update. If the value has changed, keep using the
9614-
// previous value and spawn a deferred render to update it later.
9615-
if (!objectIs(value, prevValue)) {
9603+
if (objectIs(value, prevValue)) {
9604+
// The incoming value is referentially identical to the currently rendered
9605+
// value, so we can bail out quickly.
9606+
return value;
9607+
} else {
9608+
// Received a new value that's different from the current value.
9609+
// Check if we're inside a hidden tree
9610+
if (isCurrentTreeHidden()) {
9611+
// Revealing a prerendered tree is considered the same as mounting new
9612+
// one, so we reuse the "mount" path in this case.
9613+
var resultValue = mountDeferredValueImpl(hook, value, initialValue); // Unlike during an actual mount, we need to mark this as an update if
9614+
// the value changed.
9615+
9616+
if (!objectIs(resultValue, prevValue)) {
9617+
markWorkInProgressReceivedUpdate();
9618+
}
9619+
9620+
return resultValue;
9621+
}
9622+
9623+
var shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes);
9624+
9625+
if (shouldDeferValue) {
9626+
// This is an urgent update. Since the value has changed, keep using the
9627+
// previous value and spawn a deferred render to update it later.
96169628
// Schedule a deferred render
96179629
var deferredLane = requestDeferredLane();
96189630
currentlyRenderingFiber$1.lanes = mergeLanes(
96199631
currentlyRenderingFiber$1.lanes,
96209632
deferredLane
96219633
);
9622-
markSkippedUpdateLanes(deferredLane); // Set this to true to indicate that the rendered value is inconsistent
9623-
// from the latest value. The name "baseState" doesn't really match how we
9624-
// use it because we're reusing a state hook field instead of creating a
9625-
// new one.
9634+
markSkippedUpdateLanes(deferredLane); // Reuse the previous value. We do not need to mark this as an update,
9635+
// because we did not render a new value.
96269636

9627-
hook.baseState = true;
9628-
} // Reuse the previous value
9629-
9630-
return prevValue;
9631-
} else {
9632-
// This is not an urgent update, so we can use the latest value regardless
9633-
// of what it is. No need to defer it.
9634-
// However, if we're currently inside a spawned render, then we need to mark
9635-
// this as an update to prevent the fiber from bailing out.
9636-
//
9637-
// `baseState` is true when the current value is different from the rendered
9638-
// value. The name doesn't really match how we use it because we're reusing
9639-
// a state hook field instead of creating a new one.
9640-
if (hook.baseState) {
9641-
// Flip this back to false.
9642-
hook.baseState = false;
9637+
return prevValue;
9638+
} else {
9639+
// This is not an urgent update, so we can use the latest value regardless
9640+
// of what it is. No need to defer it.
9641+
// Mark this as an update to prevent the fiber from bailing out.
96439642
markWorkInProgressReceivedUpdate();
9643+
hook.memoizedState = value;
9644+
return value;
96449645
}
9645-
9646-
hook.memoizedState = value;
9647-
return value;
96489646
}
96499647
}
96509648

@@ -10581,7 +10579,7 @@ var InvalidNestedHooksDispatcherOnRerenderInDEV = null;
1058110579
useDeferredValue: function (value, initialValue) {
1058210580
currentHookNameInDev = "useDeferredValue";
1058310581
updateHookTypesDev();
10584-
return updateDeferredValue(value);
10582+
return updateDeferredValue(value, initialValue);
1058510583
},
1058610584
useTransition: function () {
1058710585
currentHookNameInDev = "useTransition";
@@ -11037,7 +11035,7 @@ var InvalidNestedHooksDispatcherOnRerenderInDEV = null;
1103711035
currentHookNameInDev = "useDeferredValue";
1103811036
warnInvalidHookAccess();
1103911037
updateHookTypesDev();
11040-
return updateDeferredValue(value);
11038+
return updateDeferredValue(value, initialValue);
1104111039
},
1104211040
useTransition: function () {
1104311041
currentHookNameInDev = "useTransition";

0 commit comments

Comments
 (0)