@@ -30,6 +30,7 @@ import {
30
30
decoupleUpdatePriorityFromScheduler ,
31
31
enableUseRefAccessWarning ,
32
32
enableDoubleInvokingEffects ,
33
+ enableContextSelectors ,
33
34
} from 'shared/ReactFeatureFlags' ;
34
35
35
36
import {
@@ -52,7 +53,7 @@ import {
52
53
higherLanePriority ,
53
54
DefaultLanePriority ,
54
55
} from './ReactFiberLane.new' ;
55
- import { readContext } from './ReactFiberNewContext.new' ;
56
+ import { readContext , readContextInsideHook } from './ReactFiberNewContext.new' ;
56
57
import { HostRoot , CacheComponent } from './ReactWorkTags' ;
57
58
import {
58
59
Update as UpdateEffect ,
@@ -627,6 +628,56 @@ function updateWorkInProgressHook(): Hook {
627
628
return workInProgressHook ;
628
629
}
629
630
631
+ function mountSelectedContext < C , S > (
632
+ Context : ReactContext < C > ,
633
+ selector : C => S ,
634
+ isEqual : ( ( S , S ) => boolean ) | void ,
635
+ ) : S {
636
+ if ( ! enableContextSelectors ) {
637
+ return ( undefined : any ) ;
638
+ }
639
+
640
+ const hook = mountWorkInProgressHook ( ) ;
641
+ const context = readContextInsideHook ( Context ) ;
642
+ const selection = selector ( context ) ;
643
+ hook . memoizedState = selection ;
644
+ return selection ;
645
+ }
646
+
647
+ function updateSelectedContext < C , S > (
648
+ Context : ReactContext < C > ,
649
+ selector : C => S ,
650
+ isEqual : ( ( S , S ) => boolean ) | void ,
651
+ ) : S {
652
+ if ( ! enableContextSelectors ) {
653
+ return ( undefined : any ) ;
654
+ }
655
+
656
+ const hook = updateWorkInProgressHook ( ) ;
657
+ const context = readContextInsideHook ( Context ) ;
658
+ const newSelection = selector ( context ) ;
659
+ const oldSelection : S = hook . memoizedState ;
660
+ if ( isEqual !== undefined ) {
661
+ if ( __DEV__ ) {
662
+ if ( typeof isEqual !== 'function' ) {
663
+ console . error (
664
+ 'The optional third argument to useSelectedContext must be a ' +
665
+ 'function. Instead got: %s' ,
666
+ isEqual ,
667
+ ) ;
668
+ }
669
+ }
670
+ if ( isEqual ( newSelection , oldSelection ) ) {
671
+ return oldSelection ;
672
+ }
673
+ } else if ( is ( newSelection , oldSelection ) ) {
674
+ return oldSelection ;
675
+ }
676
+ markWorkInProgressReceivedUpdate ( ) ;
677
+ hook . memoizedState = newSelection ;
678
+ return newSelection ;
679
+ }
680
+
630
681
function createFunctionComponentUpdateQueue ( ) : FunctionComponentUpdateQueue {
631
682
return {
632
683
lastEffect : null ,
@@ -1995,6 +2046,7 @@ export const ContextOnlyDispatcher: Dispatcher = {
1995
2046
1996
2047
useCallback : throwInvalidHookError ,
1997
2048
useContext : throwInvalidHookError ,
2049
+ useSelectedContext : throwInvalidHookError ,
1998
2050
useEffect : throwInvalidHookError ,
1999
2051
useImperativeHandle : throwInvalidHookError ,
2000
2052
useLayoutEffect : throwInvalidHookError ,
@@ -2020,6 +2072,7 @@ const HooksDispatcherOnMount: Dispatcher = {
2020
2072
2021
2073
useCallback : mountCallback ,
2022
2074
useContext : readContext ,
2075
+ useSelectedContext : mountSelectedContext ,
2023
2076
useEffect : mountEffect ,
2024
2077
useImperativeHandle : mountImperativeHandle ,
2025
2078
useLayoutEffect : mountLayoutEffect ,
@@ -2045,6 +2098,7 @@ const HooksDispatcherOnUpdate: Dispatcher = {
2045
2098
2046
2099
useCallback : updateCallback ,
2047
2100
useContext : readContext ,
2101
+ useSelectedContext : updateSelectedContext ,
2048
2102
useEffect : updateEffect ,
2049
2103
useImperativeHandle : updateImperativeHandle ,
2050
2104
useLayoutEffect : updateLayoutEffect ,
@@ -2070,6 +2124,7 @@ const HooksDispatcherOnRerender: Dispatcher = {
2070
2124
2071
2125
useCallback : updateCallback ,
2072
2126
useContext : readContext ,
2127
+ useSelectedContext : updateSelectedContext ,
2073
2128
useEffect : updateEffect ,
2074
2129
useImperativeHandle : updateImperativeHandle ,
2075
2130
useLayoutEffect : updateLayoutEffect ,
@@ -2138,6 +2193,21 @@ if (__DEV__) {
2138
2193
mountHookTypesDev ( ) ;
2139
2194
return readContext ( context , observedBits ) ;
2140
2195
} ,
2196
+ useSelectedContext< C , S > (
2197
+ context: ReactContext< C > ,
2198
+ selector: C => S ,
2199
+ isEqual : ( ( S , S ) => boolean ) | void ,
2200
+ ) : S {
2201
+ currentHookNameInDev = 'useSelectedContext' ;
2202
+ mountHookTypesDev ( ) ;
2203
+ const prevDispatcher = ReactCurrentDispatcher . current ;
2204
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnMountInDEV ;
2205
+ try {
2206
+ return mountSelectedContext ( context , selector , isEqual ) ;
2207
+ } finally {
2208
+ ReactCurrentDispatcher . current = prevDispatcher ;
2209
+ }
2210
+ } ,
2141
2211
useEffect (
2142
2212
create : ( ) => ( ( ) => void ) | void ,
2143
2213
deps : Array < mixed > | void | null,
@@ -2272,6 +2342,21 @@ if (__DEV__) {
2272
2342
updateHookTypesDev ( ) ;
2273
2343
return readContext ( context , observedBits ) ;
2274
2344
} ,
2345
+ useSelectedContext< C , S > (
2346
+ context: ReactContext< C > ,
2347
+ selector: C => S ,
2348
+ isEqual : ( ( S , S ) => boolean ) | void ,
2349
+ ) : S {
2350
+ currentHookNameInDev = 'useSelectedContext' ;
2351
+ updateHookTypesDev ( ) ;
2352
+ const prevDispatcher = ReactCurrentDispatcher . current ;
2353
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnMountInDEV ;
2354
+ try {
2355
+ return mountSelectedContext ( context , selector , isEqual ) ;
2356
+ } finally {
2357
+ ReactCurrentDispatcher . current = prevDispatcher ;
2358
+ }
2359
+ } ,
2275
2360
useEffect (
2276
2361
create : ( ) => ( ( ) => void ) | void ,
2277
2362
deps : Array < mixed > | void | null,
@@ -2402,6 +2487,21 @@ if (__DEV__) {
2402
2487
updateHookTypesDev ( ) ;
2403
2488
return readContext ( context , observedBits ) ;
2404
2489
} ,
2490
+ useSelectedContext< C , S > (
2491
+ context: ReactContext< C > ,
2492
+ selector: C => S ,
2493
+ isEqual : ( ( S , S ) => boolean ) | void ,
2494
+ ) : S {
2495
+ currentHookNameInDev = 'useSelectedContext' ;
2496
+ updateHookTypesDev ( ) ;
2497
+ const prevDispatcher = ReactCurrentDispatcher . current ;
2498
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnUpdateInDEV ;
2499
+ try {
2500
+ return updateSelectedContext ( context , selector , isEqual ) ;
2501
+ } finally {
2502
+ ReactCurrentDispatcher . current = prevDispatcher ;
2503
+ }
2504
+ } ,
2405
2505
useEffect (
2406
2506
create : ( ) => ( ( ) => void ) | void ,
2407
2507
deps : Array < mixed > | void | null,
@@ -2533,6 +2633,21 @@ if (__DEV__) {
2533
2633
updateHookTypesDev ( ) ;
2534
2634
return readContext ( context , observedBits ) ;
2535
2635
} ,
2636
+ useSelectedContext< C , S > (
2637
+ context: ReactContext< C > ,
2638
+ selector: C => S ,
2639
+ isEqual : ( ( S , S ) => boolean ) | void ,
2640
+ ) : S {
2641
+ currentHookNameInDev = 'useSelectedContext' ;
2642
+ updateHookTypesDev ( ) ;
2643
+ const prevDispatcher = ReactCurrentDispatcher . current ;
2644
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnRerenderInDEV ;
2645
+ try {
2646
+ return updateSelectedContext ( context , selector , isEqual ) ;
2647
+ } finally {
2648
+ ReactCurrentDispatcher . current = prevDispatcher ;
2649
+ }
2650
+ } ,
2536
2651
useEffect (
2537
2652
create : ( ) => ( ( ) => void ) | void ,
2538
2653
deps : Array < mixed > | void | null,
@@ -2666,6 +2781,22 @@ if (__DEV__) {
2666
2781
mountHookTypesDev ( ) ;
2667
2782
return readContext ( context , observedBits ) ;
2668
2783
} ,
2784
+ useSelectedContext< C , S > (
2785
+ context: ReactContext< C > ,
2786
+ selector: C => S ,
2787
+ isEqual : ( ( S , S ) => boolean ) | void ,
2788
+ ) : S {
2789
+ currentHookNameInDev = 'useSelectedContext' ;
2790
+ warnInvalidHookAccess ( ) ;
2791
+ mountHookTypesDev ( ) ;
2792
+ const prevDispatcher = ReactCurrentDispatcher . current ;
2793
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnMountInDEV ;
2794
+ try {
2795
+ return mountSelectedContext ( context , selector , isEqual ) ;
2796
+ } finally {
2797
+ ReactCurrentDispatcher . current = prevDispatcher ;
2798
+ }
2799
+ } ,
2669
2800
useEffect (
2670
2801
create : ( ) => ( ( ) => void ) | void ,
2671
2802
deps : Array < mixed > | void | null,
@@ -2811,6 +2942,22 @@ if (__DEV__) {
2811
2942
updateHookTypesDev ( ) ;
2812
2943
return readContext ( context , observedBits ) ;
2813
2944
} ,
2945
+ useSelectedContext< C , S > (
2946
+ context: ReactContext< C > ,
2947
+ selector: C => S ,
2948
+ isEqual : ( ( S , S ) => boolean ) | void ,
2949
+ ) : S {
2950
+ currentHookNameInDev = 'useSelectedContext' ;
2951
+ warnInvalidHookAccess ( ) ;
2952
+ updateHookTypesDev ( ) ;
2953
+ const prevDispatcher = ReactCurrentDispatcher . current ;
2954
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnUpdateInDEV ;
2955
+ try {
2956
+ return updateSelectedContext ( context , selector , isEqual ) ;
2957
+ } finally {
2958
+ ReactCurrentDispatcher . current = prevDispatcher ;
2959
+ }
2960
+ } ,
2814
2961
useEffect (
2815
2962
create : ( ) => ( ( ) => void ) | void ,
2816
2963
deps : Array < mixed > | void | null,
@@ -2957,6 +3104,22 @@ if (__DEV__) {
2957
3104
updateHookTypesDev ( ) ;
2958
3105
return readContext ( context , observedBits ) ;
2959
3106
} ,
3107
+ useSelectedContext< C , S > (
3108
+ context: ReactContext< C > ,
3109
+ selector: C => S ,
3110
+ isEqual : ( ( S , S ) => boolean ) | void ,
3111
+ ) : S {
3112
+ currentHookNameInDev = 'useSelectedContext' ;
3113
+ warnInvalidHookAccess ( ) ;
3114
+ updateHookTypesDev ( ) ;
3115
+ const prevDispatcher = ReactCurrentDispatcher . current ;
3116
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnUpdateInDEV ;
3117
+ try {
3118
+ return updateSelectedContext ( context , selector , isEqual ) ;
3119
+ } finally {
3120
+ ReactCurrentDispatcher . current = prevDispatcher ;
3121
+ }
3122
+ } ,
2960
3123
useEffect (
2961
3124
create : ( ) => ( ( ) => void ) | void ,
2962
3125
deps : Array < mixed > | void | null,
0 commit comments