@@ -41,6 +41,7 @@ import {
41
41
debugRenderPhaseSideEffectsForStrictMode ,
42
42
enableAsyncActions ,
43
43
enableFormActions ,
44
+ enableUseDeferredValueInitialArg ,
44
45
} from 'shared/ReactFeatureFlags' ;
45
46
import {
46
47
REACT_CONTEXT_TYPE ,
@@ -2638,33 +2639,69 @@ function updateMemo<T>(
2638
2639
return nextValue ;
2639
2640
}
2640
2641
2641
- function mountDeferredValue < T > ( value : T ) : T {
2642
+ function mountDeferredValue < T > ( value : T , initialValue ? : T ) : T {
2642
2643
const hook = mountWorkInProgressHook ( ) ;
2643
- hook . memoizedState = value ;
2644
- return value ;
2644
+ return mountDeferredValueImpl ( hook , value , initialValue ) ;
2645
2645
}
2646
2646
2647
- function updateDeferredValue < T > ( value : T ) : T {
2647
+ function updateDeferredValue < T > ( value : T , initialValue ? : T ) : T {
2648
2648
const hook = updateWorkInProgressHook ( ) ;
2649
2649
const resolvedCurrentHook : Hook = ( currentHook : any ) ;
2650
2650
const prevValue : T = resolvedCurrentHook . memoizedState ;
2651
- return updateDeferredValueImpl ( hook , prevValue , value ) ;
2651
+ return updateDeferredValueImpl ( hook , prevValue , value , initialValue ) ;
2652
2652
}
2653
2653
2654
- function rerenderDeferredValue < T > ( value : T ) : T {
2654
+ function rerenderDeferredValue < T > ( value : T , initialValue ? : T ) : T {
2655
2655
const hook = updateWorkInProgressHook ( ) ;
2656
2656
if ( currentHook === null ) {
2657
2657
// This is a rerender during a mount.
2658
- hook . memoizedState = value ;
2659
- return value ;
2658
+ return mountDeferredValueImpl ( hook , value , initialValue ) ;
2660
2659
} else {
2661
2660
// This is a rerender during an update.
2662
2661
const prevValue : T = currentHook . memoizedState ;
2663
- return updateDeferredValueImpl ( hook , prevValue , value ) ;
2662
+ return updateDeferredValueImpl ( hook , prevValue , value , initialValue ) ;
2664
2663
}
2665
2664
}
2666
2665
2667
- function updateDeferredValueImpl< T > (hook: Hook, prevValue: T, value: T): T {
2666
+ function mountDeferredValueImpl< T > (hook: Hook, value: T, initialValue?: T): T {
2667
+ if ( enableUseDeferredValueInitialArg && initialValue !== undefined ) {
2668
+ // When `initialValue` is provided, we defer the initial render even if the
2669
+ // current render is not synchronous.
2670
+ // TODO: However, to avoid waterfalls, we should not defer if this render
2671
+ // was itself spawned by an earlier useDeferredValue. Plan is to add a
2672
+ // Deferred lane to track this.
2673
+ hook . memoizedState = initialValue ;
2674
+
2675
+ // Schedule a deferred render
2676
+ const deferredLane = claimNextTransitionLane ( ) ;
2677
+ currentlyRenderingFiber . lanes = mergeLanes (
2678
+ currentlyRenderingFiber . lanes ,
2679
+ deferredLane ,
2680
+ ) ;
2681
+ markSkippedUpdateLanes ( deferredLane ) ;
2682
+
2683
+ // Set this to true to indicate that the rendered value is inconsistent
2684
+ // from the latest value. The name "baseState" doesn't really match how we
2685
+ // use it because we're reusing a state hook field instead of creating a
2686
+ // new one.
2687
+ hook . baseState = true ;
2688
+
2689
+ return initialValue ;
2690
+ } else {
2691
+ hook . memoizedState = value ;
2692
+ return value ;
2693
+ }
2694
+ }
2695
+
2696
+ function updateDeferredValueImpl < T > (
2697
+ hook: Hook,
2698
+ prevValue: T,
2699
+ value: T,
2700
+ initialValue: ?T,
2701
+ ): T {
2702
+ // TODO: We should also check if this component is going from
2703
+ // hidden -> visible. If so, it should use the initialValue arg.
2704
+
2668
2705
const shouldDeferValue = ! includesOnlyNonUrgentLanes ( renderLanes ) ;
2669
2706
if ( shouldDeferValue ) {
2670
2707
// This is an urgent update. If the value has changed, keep using the
@@ -3633,10 +3670,10 @@ if (__DEV__) {
3633
3670
mountHookTypesDev ( ) ;
3634
3671
return mountDebugValue ( value , formatterFn ) ;
3635
3672
} ,
3636
- useDeferredValue< T > (value: T): T {
3673
+ useDeferredValue< T > (value: T, initialValue?: T ): T {
3637
3674
currentHookNameInDev = 'useDeferredValue' ;
3638
3675
mountHookTypesDev ( ) ;
3639
- return mountDeferredValue ( value ) ;
3676
+ return mountDeferredValue ( value , initialValue ) ;
3640
3677
} ,
3641
3678
useTransition(): [boolean, (() => void ) => void ] {
3642
3679
currentHookNameInDev = 'useTransition' ;
@@ -3802,10 +3839,10 @@ if (__DEV__) {
3802
3839
updateHookTypesDev ( ) ;
3803
3840
return mountDebugValue ( value , formatterFn ) ;
3804
3841
} ,
3805
- useDeferredValue< T > (value: T): T {
3842
+ useDeferredValue< T > (value: T, initialValue?: T ): T {
3806
3843
currentHookNameInDev = 'useDeferredValue' ;
3807
3844
updateHookTypesDev ( ) ;
3808
- return mountDeferredValue ( value ) ;
3845
+ return mountDeferredValue ( value , initialValue ) ;
3809
3846
} ,
3810
3847
useTransition(): [boolean, (() => void ) => void ] {
3811
3848
currentHookNameInDev = 'useTransition' ;
@@ -3975,10 +4012,10 @@ if (__DEV__) {
3975
4012
updateHookTypesDev ( ) ;
3976
4013
return updateDebugValue ( value , formatterFn ) ;
3977
4014
} ,
3978
- useDeferredValue< T > (value: T): T {
4015
+ useDeferredValue< T > (value: T, initialValue?: T ): T {
3979
4016
currentHookNameInDev = 'useDeferredValue' ;
3980
4017
updateHookTypesDev ( ) ;
3981
- return updateDeferredValue ( value ) ;
4018
+ return updateDeferredValue ( value , initialValue ) ;
3982
4019
} ,
3983
4020
useTransition(): [boolean, (() => void ) => void ] {
3984
4021
currentHookNameInDev = 'useTransition' ;
@@ -4147,10 +4184,10 @@ if (__DEV__) {
4147
4184
updateHookTypesDev ( ) ;
4148
4185
return updateDebugValue ( value , formatterFn ) ;
4149
4186
} ,
4150
- useDeferredValue< T > (value: T): T {
4187
+ useDeferredValue< T > (value: T, initialValue?: T ): T {
4151
4188
currentHookNameInDev = 'useDeferredValue' ;
4152
4189
updateHookTypesDev ( ) ;
4153
- return rerenderDeferredValue ( value ) ;
4190
+ return rerenderDeferredValue ( value , initialValue ) ;
4154
4191
} ,
4155
4192
useTransition(): [boolean, (() => void ) => void ] {
4156
4193
currentHookNameInDev = 'useTransition' ;
@@ -4331,11 +4368,11 @@ if (__DEV__) {
4331
4368
mountHookTypesDev ( ) ;
4332
4369
return mountDebugValue ( value , formatterFn ) ;
4333
4370
} ,
4334
- useDeferredValue< T > (value: T): T {
4371
+ useDeferredValue< T > (value: T, initialValue?: T ): T {
4335
4372
currentHookNameInDev = 'useDeferredValue' ;
4336
4373
warnInvalidHookAccess ( ) ;
4337
4374
mountHookTypesDev ( ) ;
4338
- return mountDeferredValue ( value ) ;
4375
+ return mountDeferredValue ( value , initialValue ) ;
4339
4376
} ,
4340
4377
useTransition(): [boolean, (() => void ) => void ] {
4341
4378
currentHookNameInDev = 'useTransition' ;
@@ -4529,11 +4566,11 @@ if (__DEV__) {
4529
4566
updateHookTypesDev ( ) ;
4530
4567
return updateDebugValue ( value , formatterFn ) ;
4531
4568
} ,
4532
- useDeferredValue< T > (value: T): T {
4569
+ useDeferredValue< T > (value: T, initialValue?: T ): T {
4533
4570
currentHookNameInDev = 'useDeferredValue' ;
4534
4571
warnInvalidHookAccess ( ) ;
4535
4572
updateHookTypesDev ( ) ;
4536
- return updateDeferredValue ( value ) ;
4573
+ return updateDeferredValue ( value , initialValue ) ;
4537
4574
} ,
4538
4575
useTransition(): [boolean, (() => void ) => void ] {
4539
4576
currentHookNameInDev = 'useTransition' ;
@@ -4727,11 +4764,11 @@ if (__DEV__) {
4727
4764
updateHookTypesDev ( ) ;
4728
4765
return updateDebugValue ( value , formatterFn ) ;
4729
4766
} ,
4730
- useDeferredValue< T > (value: T): T {
4767
+ useDeferredValue< T > (value: T, initialValue?: T ): T {
4731
4768
currentHookNameInDev = 'useDeferredValue' ;
4732
4769
warnInvalidHookAccess ( ) ;
4733
4770
updateHookTypesDev ( ) ;
4734
- return rerenderDeferredValue ( value ) ;
4771
+ return rerenderDeferredValue ( value , initialValue ) ;
4735
4772
} ,
4736
4773
useTransition(): [boolean, (() => void ) => void ] {
4737
4774
currentHookNameInDev = 'useTransition' ;
0 commit comments