@@ -41,6 +41,7 @@ import {
4141 debugRenderPhaseSideEffectsForStrictMode ,
4242 enableAsyncActions ,
4343 enableFormActions ,
44+ enableUseDeferredValueInitialArg ,
4445} from 'shared/ReactFeatureFlags' ;
4546import {
4647 REACT_CONTEXT_TYPE ,
@@ -2638,33 +2639,69 @@ function updateMemo<T>(
26382639 return nextValue ;
26392640}
26402641
2641- function mountDeferredValue < T > ( value : T ) : T {
2642+ function mountDeferredValue < T > ( value : T , initialValue ? : T ) : T {
26422643 const hook = mountWorkInProgressHook ( ) ;
2643- hook . memoizedState = value ;
2644- return value ;
2644+ return mountDeferredValueImpl ( hook , value , initialValue ) ;
26452645}
26462646
2647- function updateDeferredValue < T > ( value : T ) : T {
2647+ function updateDeferredValue < T > ( value : T , initialValue ? : T ) : T {
26482648 const hook = updateWorkInProgressHook ( ) ;
26492649 const resolvedCurrentHook : Hook = ( currentHook : any ) ;
26502650 const prevValue : T = resolvedCurrentHook . memoizedState ;
2651- return updateDeferredValueImpl ( hook , prevValue , value ) ;
2651+ return updateDeferredValueImpl ( hook , prevValue , value , initialValue ) ;
26522652}
26532653
2654- function rerenderDeferredValue < T > ( value : T ) : T {
2654+ function rerenderDeferredValue < T > ( value : T , initialValue ? : T ) : T {
26552655 const hook = updateWorkInProgressHook ( ) ;
26562656 if ( currentHook === null ) {
26572657 // This is a rerender during a mount.
2658- hook . memoizedState = value ;
2659- return value ;
2658+ return mountDeferredValueImpl ( hook , value , initialValue ) ;
26602659 } else {
26612660 // This is a rerender during an update.
26622661 const prevValue : T = currentHook . memoizedState ;
2663- return updateDeferredValueImpl ( hook , prevValue , value ) ;
2662+ return updateDeferredValueImpl ( hook , prevValue , value , initialValue ) ;
26642663 }
26652664}
26662665
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+
26682705 const shouldDeferValue = ! includesOnlyNonUrgentLanes ( renderLanes ) ;
26692706 if ( shouldDeferValue ) {
26702707 // This is an urgent update. If the value has changed, keep using the
@@ -3633,10 +3670,10 @@ if (__DEV__) {
36333670 mountHookTypesDev ( ) ;
36343671 return mountDebugValue ( value , formatterFn ) ;
36353672 } ,
3636- useDeferredValue< T > (value: T): T {
3673+ useDeferredValue< T > (value: T, initialValue?: T ): T {
36373674 currentHookNameInDev = 'useDeferredValue' ;
36383675 mountHookTypesDev ( ) ;
3639- return mountDeferredValue ( value ) ;
3676+ return mountDeferredValue ( value , initialValue ) ;
36403677 } ,
36413678 useTransition(): [boolean, (() => void ) => void ] {
36423679 currentHookNameInDev = 'useTransition' ;
@@ -3802,10 +3839,10 @@ if (__DEV__) {
38023839 updateHookTypesDev ( ) ;
38033840 return mountDebugValue ( value , formatterFn ) ;
38043841 } ,
3805- useDeferredValue< T > (value: T): T {
3842+ useDeferredValue< T > (value: T, initialValue?: T ): T {
38063843 currentHookNameInDev = 'useDeferredValue' ;
38073844 updateHookTypesDev ( ) ;
3808- return mountDeferredValue ( value ) ;
3845+ return mountDeferredValue ( value , initialValue ) ;
38093846 } ,
38103847 useTransition(): [boolean, (() => void ) => void ] {
38113848 currentHookNameInDev = 'useTransition' ;
@@ -3975,10 +4012,10 @@ if (__DEV__) {
39754012 updateHookTypesDev ( ) ;
39764013 return updateDebugValue ( value , formatterFn ) ;
39774014 } ,
3978- useDeferredValue< T > (value: T): T {
4015+ useDeferredValue< T > (value: T, initialValue?: T ): T {
39794016 currentHookNameInDev = 'useDeferredValue' ;
39804017 updateHookTypesDev ( ) ;
3981- return updateDeferredValue ( value ) ;
4018+ return updateDeferredValue ( value , initialValue ) ;
39824019 } ,
39834020 useTransition(): [boolean, (() => void ) => void ] {
39844021 currentHookNameInDev = 'useTransition' ;
@@ -4147,10 +4184,10 @@ if (__DEV__) {
41474184 updateHookTypesDev ( ) ;
41484185 return updateDebugValue ( value , formatterFn ) ;
41494186 } ,
4150- useDeferredValue< T > (value: T): T {
4187+ useDeferredValue< T > (value: T, initialValue?: T ): T {
41514188 currentHookNameInDev = 'useDeferredValue' ;
41524189 updateHookTypesDev ( ) ;
4153- return rerenderDeferredValue ( value ) ;
4190+ return rerenderDeferredValue ( value , initialValue ) ;
41544191 } ,
41554192 useTransition(): [boolean, (() => void ) => void ] {
41564193 currentHookNameInDev = 'useTransition' ;
@@ -4331,11 +4368,11 @@ if (__DEV__) {
43314368 mountHookTypesDev ( ) ;
43324369 return mountDebugValue ( value , formatterFn ) ;
43334370 } ,
4334- useDeferredValue< T > (value: T): T {
4371+ useDeferredValue< T > (value: T, initialValue?: T ): T {
43354372 currentHookNameInDev = 'useDeferredValue' ;
43364373 warnInvalidHookAccess ( ) ;
43374374 mountHookTypesDev ( ) ;
4338- return mountDeferredValue ( value ) ;
4375+ return mountDeferredValue ( value , initialValue ) ;
43394376 } ,
43404377 useTransition(): [boolean, (() => void ) => void ] {
43414378 currentHookNameInDev = 'useTransition' ;
@@ -4529,11 +4566,11 @@ if (__DEV__) {
45294566 updateHookTypesDev ( ) ;
45304567 return updateDebugValue ( value , formatterFn ) ;
45314568 } ,
4532- useDeferredValue< T > (value: T): T {
4569+ useDeferredValue< T > (value: T, initialValue?: T ): T {
45334570 currentHookNameInDev = 'useDeferredValue' ;
45344571 warnInvalidHookAccess ( ) ;
45354572 updateHookTypesDev ( ) ;
4536- return updateDeferredValue ( value ) ;
4573+ return updateDeferredValue ( value , initialValue ) ;
45374574 } ,
45384575 useTransition(): [boolean, (() => void ) => void ] {
45394576 currentHookNameInDev = 'useTransition' ;
@@ -4727,11 +4764,11 @@ if (__DEV__) {
47274764 updateHookTypesDev ( ) ;
47284765 return updateDebugValue ( value , formatterFn ) ;
47294766 } ,
4730- useDeferredValue< T > (value: T): T {
4767+ useDeferredValue< T > (value: T, initialValue?: T ): T {
47314768 currentHookNameInDev = 'useDeferredValue' ;
47324769 warnInvalidHookAccess ( ) ;
47334770 updateHookTypesDev ( ) ;
4734- return rerenderDeferredValue ( value ) ;
4771+ return rerenderDeferredValue ( value , initialValue ) ;
47354772 } ,
47364773 useTransition(): [boolean, (() => void ) => void ] {
47374774 currentHookNameInDev = 'useTransition' ;
0 commit comments