41
debugRenderPhaseSideEffectsForStrictMode,
42
enableAsyncActions,
43
enableFormActions,
44
+ enableUseDeferredValueInitialArg,
45
} from 'shared/ReactFeatureFlags';
46
import {
47
REACT_CONTEXT_TYPE,
2639
return nextValue;
2640
}
2641
2641
-function mountDeferredValue<T>(value: T): T {
2642
+function mountDeferredValue<T>(value: T, initialValue?: T): T {
2643
const hook = mountWorkInProgressHook();
2643
- hook.memoizedState = value;
2644
- return value;
2644
+ return mountDeferredValueImpl(hook, value, initialValue);
2645
}
2646
2647
-function updateDeferredValue<T>(value: T): T {
2647
+function updateDeferredValue<T>(value: T, initialValue?: T): T {
2648
const hook = updateWorkInProgressHook();
2649
const resolvedCurrentHook: Hook = (currentHook: any);
2650
const prevValue: T = resolvedCurrentHook.memoizedState;
2651
- return updateDeferredValueImpl(hook, prevValue, value);
2651
+ return updateDeferredValueImpl(hook, prevValue, value, initialValue);
2652
}
2653
2654
-function rerenderDeferredValue<T>(value: T): T {
2654
+function rerenderDeferredValue<T>(value: T, initialValue?: T): T {
2655
const hook = updateWorkInProgressHook();
2656
if (currentHook === null) {
2657
// This is a rerender during a mount.
2658
- hook.memoizedState = value;
2659
- return value;
2658
+ return mountDeferredValueImpl(hook, value, initialValue);
2659
} else {
2660
// This is a rerender during an update.
2661
const prevValue: T = currentHook.memoizedState;
2663
- return updateDeferredValueImpl(hook, prevValue, value);
2662
+ return updateDeferredValueImpl(hook, prevValue, value, initialValue);
2663
}
2664
}
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
+
2705
const shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes);
2706
if (shouldDeferValue) {
2707
// This is an urgent update. If the value has changed, keep using the
3670
mountHookTypesDev();
3671
return mountDebugValue(value, formatterFn);
3672
},
3636
- useDeferredValue<T>(value: T): T {
3673
+ useDeferredValue<T>(value: T, initialValue?: T): T {
3674
currentHookNameInDev = 'useDeferredValue';
3675
mountHookTypesDev();
3639
- return mountDeferredValue(value);
3676
+ return mountDeferredValue(value, initialValue);
3677
},
3678
useTransition(): [boolean, (() => void) => void] {
3679
currentHookNameInDev = 'useTransition';
3839
updateHookTypesDev();
3840
return mountDebugValue(value, formatterFn);
3841
},
3805
- useDeferredValue<T>(value: T): T {
3842
+ useDeferredValue<T>(value: T, initialValue?: T): T {
3843
currentHookNameInDev = 'useDeferredValue';
3844
updateHookTypesDev();
3808
- return mountDeferredValue(value);
3845
+ return mountDeferredValue(value, initialValue);
3846
},
3847
useTransition(): [boolean, (() => void) => void] {
3848
currentHookNameInDev = 'useTransition';
4012
updateHookTypesDev();
4013
return updateDebugValue(value, formatterFn);
4014
},
3978
- useDeferredValue<T>(value: T): T {
4015
+ useDeferredValue<T>(value: T, initialValue?: T): T {
4016
currentHookNameInDev = 'useDeferredValue';
4017
updateHookTypesDev();
3981
- return updateDeferredValue(value);
4018
+ return updateDeferredValue(value, initialValue);
4019
},
4020
useTransition(): [boolean, (() => void) => void] {
4021
currentHookNameInDev = 'useTransition';
4184
updateHookTypesDev();
4185
return updateDebugValue(value, formatterFn);
4186
},
4150
- useDeferredValue<T>(value: T): T {
4187
+ useDeferredValue<T>(value: T, initialValue?: T): T {
4188
currentHookNameInDev = 'useDeferredValue';
4189
updateHookTypesDev();
4153
- return rerenderDeferredValue(value);
4190
+ return rerenderDeferredValue(value, initialValue);
4191
},
4192
useTransition(): [boolean, (() => void) => void] {
4193
currentHookNameInDev = 'useTransition';
4368
mountHookTypesDev();
4369
return mountDebugValue(value, formatterFn);
4370
},
4334
- useDeferredValue<T>(value: T): T {
4371
+ useDeferredValue<T>(value: T, initialValue?: T): T {
4372
currentHookNameInDev = 'useDeferredValue';
4373
warnInvalidHookAccess();
4374
mountHookTypesDev();
4338
- return mountDeferredValue(value);
4375
+ return mountDeferredValue(value, initialValue);
4376
},
4377
useTransition(): [boolean, (() => void) => void] {
4378
currentHookNameInDev = 'useTransition';
4566
updateHookTypesDev();
4567
return updateDebugValue(value, formatterFn);
4568
},
4532
- useDeferredValue<T>(value: T): T {
4569
+ useDeferredValue<T>(value: T, initialValue?: T): T {
4570
currentHookNameInDev = 'useDeferredValue';
4571
warnInvalidHookAccess();
4572
updateHookTypesDev();
4536
- return updateDeferredValue(value);
4573
+ return updateDeferredValue(value, initialValue);
4574
},
4575
useTransition(): [boolean, (() => void) => void] {
4576
currentHookNameInDev = 'useTransition';
4764
updateHookTypesDev();
4765
return updateDebugValue(value, formatterFn);
4766
},
4730
- useDeferredValue<T>(value: T): T {
4767
+ useDeferredValue<T>(value: T, initialValue?: T): T {
4768
currentHookNameInDev = 'useDeferredValue';
4769
warnInvalidHookAccess();
4770
updateHookTypesDev();
4734
- return rerenderDeferredValue(value);
4771
+ return rerenderDeferredValue(value, initialValue);
4772
},
4773
useTransition(): [boolean, (() => void) => void] {
4774
currentHookNameInDev = 'useTransition';