@@ -1927,32 +1927,59 @@ function updateMemo<T>(
1927
1927
return nextValue;
1928
1928
}
1929
1929
1930
- function mountDeferredValue < T > (value: T): T {
1930
+ function mountDeferredValue < T > (value: T, initialValue?: T ): T {
1931
1931
const hook = mountWorkInProgressHook ( ) ;
1932
- hook . memoizedState = value ;
1933
- return value ;
1932
+ return mountDeferredValueImpl ( hook , value , initialValue ) ;
1934
1933
}
1935
1934
1936
- function updateDeferredValue< T > (value: T): T {
1935
+ function updateDeferredValue< T > (value: T, initialValue?: T ): T {
1937
1936
const hook = updateWorkInProgressHook ( ) ;
1938
1937
const resolvedCurrentHook : Hook = ( currentHook : any ) ;
1939
1938
const prevValue : T = resolvedCurrentHook . memoizedState ;
1940
1939
return updateDeferredValueImpl ( hook , prevValue , value ) ;
1941
1940
}
1942
1941
1943
- function rerenderDeferredValue< T > (value: T): T {
1942
+ function rerenderDeferredValue< T > (value: T, initialValue?: T ): T {
1944
1943
const hook = updateWorkInProgressHook ( ) ;
1945
1944
if ( currentHook === null ) {
1946
1945
// This is a rerender during a mount.
1947
- hook . memoizedState = value ;
1948
- return value ;
1946
+ return mountDeferredValueImpl ( hook , value , initialValue ) ;
1949
1947
} else {
1950
1948
// This is a rerender during an update.
1951
1949
const prevValue : T = currentHook . memoizedState ;
1952
1950
return updateDeferredValueImpl ( hook , prevValue , value ) ;
1953
1951
}
1954
1952
}
1955
1953
1954
+ function mountDeferredValueImpl < T > (hook: Hook, value: T, initialValue?: T): T {
1955
+ // During hydration, if an initial value is provided, we always use that one
1956
+ // regardless of the render priority. This means you can use it for
1957
+ // progressive enhancement. Otherwise, we only use the initial value if the
1958
+ // render is urgent — same logic as during an update.
1959
+ if (
1960
+ ( getIsHydrating ( ) || ! includesOnlyNonUrgentLanes ( renderLanes ) ) &&
1961
+ initialValue !== undefined &&
1962
+ ! is ( value , initialValue )
1963
+ ) {
1964
+ // Spawn a deferred render
1965
+ const deferredLane = claimNextTransitionLane ( ) ;
1966
+ currentlyRenderingFiber . lanes = mergeLanes (
1967
+ currentlyRenderingFiber . lanes ,
1968
+ deferredLane ,
1969
+ ) ;
1970
+ markSkippedUpdateLanes ( deferredLane ) ;
1971
+
1972
+ // Set this to true to indicate that the rendered value is inconsistent
1973
+ // from the latest value. The name "baseState" doesn't really match how we
1974
+ // use it because we're reusing a state hook field instead of creating a
1975
+ // new one.
1976
+ hook . baseState = true ;
1977
+ value = initialValue ;
1978
+ }
1979
+ hook.memoizedState = value;
1980
+ return value;
1981
+ }
1982
+
1956
1983
function updateDeferredValueImpl < T > (hook: Hook, prevValue: T, value: T): T {
1957
1984
const shouldDeferValue = ! includesOnlyNonUrgentLanes ( renderLanes ) ;
1958
1985
if ( shouldDeferValue ) {
@@ -2664,10 +2691,10 @@ if (__DEV__) {
2664
2691
mountHookTypesDev ( ) ;
2665
2692
return mountDebugValue ( value , formatterFn ) ;
2666
2693
} ,
2667
- useDeferredValue< T > (value: T): T {
2694
+ useDeferredValue< T > (value: T, initialValue?: T ): T {
2668
2695
currentHookNameInDev = 'useDeferredValue' ;
2669
2696
mountHookTypesDev ( ) ;
2670
- return mountDeferredValue ( value ) ;
2697
+ return mountDeferredValue ( value , initialValue ) ;
2671
2698
} ,
2672
2699
useTransition(): [boolean, (() => void ) => void ] {
2673
2700
currentHookNameInDev = 'useTransition' ;
@@ -2806,10 +2833,10 @@ if (__DEV__) {
2806
2833
updateHookTypesDev ( ) ;
2807
2834
return mountDebugValue ( value , formatterFn ) ;
2808
2835
} ,
2809
- useDeferredValue< T > (value: T): T {
2836
+ useDeferredValue< T > (value: T, initialValue?: T ): T {
2810
2837
currentHookNameInDev = 'useDeferredValue' ;
2811
2838
updateHookTypesDev ( ) ;
2812
- return mountDeferredValue ( value ) ;
2839
+ return mountDeferredValue ( value , initialValue ) ;
2813
2840
} ,
2814
2841
useTransition(): [boolean, (() => void ) => void ] {
2815
2842
currentHookNameInDev = 'useTransition' ;
@@ -2948,10 +2975,10 @@ if (__DEV__) {
2948
2975
updateHookTypesDev ( ) ;
2949
2976
return updateDebugValue ( value , formatterFn ) ;
2950
2977
} ,
2951
- useDeferredValue< T > (value: T): T {
2978
+ useDeferredValue< T > (value: T, initialValue?: T ): T {
2952
2979
currentHookNameInDev = 'useDeferredValue' ;
2953
2980
updateHookTypesDev ( ) ;
2954
- return updateDeferredValue ( value ) ;
2981
+ return updateDeferredValue ( value , initialValue ) ;
2955
2982
} ,
2956
2983
useTransition(): [boolean, (() => void ) => void ] {
2957
2984
currentHookNameInDev = 'useTransition' ;
@@ -3091,10 +3118,10 @@ if (__DEV__) {
3091
3118
updateHookTypesDev ( ) ;
3092
3119
return updateDebugValue ( value , formatterFn ) ;
3093
3120
} ,
3094
- useDeferredValue< T > (value: T): T {
3121
+ useDeferredValue< T > (value: T, initialValue?: T ): T {
3095
3122
currentHookNameInDev = 'useDeferredValue' ;
3096
3123
updateHookTypesDev ( ) ;
3097
- return rerenderDeferredValue ( value ) ;
3124
+ return rerenderDeferredValue ( value , initialValue ) ;
3098
3125
} ,
3099
3126
useTransition(): [boolean, (() => void ) => void ] {
3100
3127
currentHookNameInDev = 'useTransition' ;
@@ -3245,11 +3272,11 @@ if (__DEV__) {
3245
3272
mountHookTypesDev ( ) ;
3246
3273
return mountDebugValue ( value , formatterFn ) ;
3247
3274
} ,
3248
- useDeferredValue< T > (value: T): T {
3275
+ useDeferredValue< T > (value: T, initialValue?: T ): T {
3249
3276
currentHookNameInDev = 'useDeferredValue' ;
3250
3277
warnInvalidHookAccess ( ) ;
3251
3278
mountHookTypesDev ( ) ;
3252
- return mountDeferredValue ( value ) ;
3279
+ return mountDeferredValue ( value , initialValue ) ;
3253
3280
} ,
3254
3281
useTransition(): [boolean, (() => void ) => void ] {
3255
3282
currentHookNameInDev = 'useTransition' ;
@@ -3404,11 +3431,11 @@ if (__DEV__) {
3404
3431
updateHookTypesDev ( ) ;
3405
3432
return updateDebugValue ( value , formatterFn ) ;
3406
3433
} ,
3407
- useDeferredValue< T > (value: T): T {
3434
+ useDeferredValue< T > (value: T, initialValue?: T ): T {
3408
3435
currentHookNameInDev = 'useDeferredValue' ;
3409
3436
warnInvalidHookAccess ( ) ;
3410
3437
updateHookTypesDev ( ) ;
3411
- return updateDeferredValue ( value ) ;
3438
+ return updateDeferredValue ( value , initialValue ) ;
3412
3439
} ,
3413
3440
useTransition(): [boolean, (() => void ) => void ] {
3414
3441
currentHookNameInDev = 'useTransition' ;
@@ -3564,11 +3591,11 @@ if (__DEV__) {
3564
3591
updateHookTypesDev ( ) ;
3565
3592
return updateDebugValue ( value , formatterFn ) ;
3566
3593
} ,
3567
- useDeferredValue< T > (value: T): T {
3594
+ useDeferredValue< T > (value: T, initialValue?: T ): T {
3568
3595
currentHookNameInDev = 'useDeferredValue' ;
3569
3596
warnInvalidHookAccess ( ) ;
3570
3597
updateHookTypesDev ( ) ;
3571
- return rerenderDeferredValue ( value ) ;
3598
+ return rerenderDeferredValue ( value , initialValue ) ;
3572
3599
} ,
3573
3600
useTransition(): [boolean, (() => void ) => void ] {
3574
3601
currentHookNameInDev = 'useTransition' ;
0 commit comments