@@ -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 {
@@ -54,7 +55,7 @@ import {
54
55
higherLanePriority ,
55
56
DefaultLanePriority ,
56
57
} from './ReactFiberLane.new' ;
57
- import { readContext } from './ReactFiberNewContext.new' ;
58
+ import { readContext , readContextInsideHook } from './ReactFiberNewContext.new' ;
58
59
import { HostRoot , CacheComponent } from './ReactWorkTags' ;
59
60
import {
60
61
Update as UpdateEffect ,
@@ -634,6 +635,56 @@ function updateWorkInProgressHook(): Hook {
634
635
return workInProgressHook ;
635
636
}
636
637
638
+ function mountSelectedContext < C , S > (
639
+ Context : ReactContext < C > ,
640
+ selector : C => S ,
641
+ isEqual : ( ( S , S ) => boolean ) | void ,
642
+ ) : S {
643
+ if ( ! enableContextSelectors ) {
644
+ return ( undefined : any ) ;
645
+ }
646
+
647
+ const hook = mountWorkInProgressHook ( ) ;
648
+ const context = readContextInsideHook ( Context ) ;
649
+ const selection = selector ( context ) ;
650
+ hook . memoizedState = selection ;
651
+ return selection ;
652
+ }
653
+
654
+ function updateSelectedContext < C , S > (
655
+ Context : ReactContext < C > ,
656
+ selector : C => S ,
657
+ isEqual : ( ( S , S ) => boolean ) | void ,
658
+ ) : S {
659
+ if ( ! enableContextSelectors ) {
660
+ return ( undefined : any ) ;
661
+ }
662
+
663
+ const hook = updateWorkInProgressHook ( ) ;
664
+ const context = readContextInsideHook ( Context ) ;
665
+ const newSelection = selector ( context ) ;
666
+ const oldSelection : S = hook . memoizedState ;
667
+ if ( isEqual !== undefined ) {
668
+ if ( __DEV__ ) {
669
+ if ( typeof isEqual !== 'function' ) {
670
+ console . error (
671
+ 'The optional third argument to useSelectedContext must be a ' +
672
+ 'function. Instead got: %s' ,
673
+ isEqual ,
674
+ ) ;
675
+ }
676
+ }
677
+ if ( isEqual ( newSelection , oldSelection ) ) {
678
+ return oldSelection ;
679
+ }
680
+ } else if ( is ( newSelection , oldSelection ) ) {
681
+ return oldSelection ;
682
+ }
683
+ markWorkInProgressReceivedUpdate ( ) ;
684
+ hook . memoizedState = newSelection ;
685
+ return newSelection ;
686
+ }
687
+
637
688
function createFunctionComponentUpdateQueue ( ) : FunctionComponentUpdateQueue {
638
689
return {
639
690
lastEffect : null ,
@@ -2068,6 +2119,7 @@ export const ContextOnlyDispatcher: Dispatcher = {
2068
2119
2069
2120
useCallback : throwInvalidHookError ,
2070
2121
useContext : throwInvalidHookError ,
2122
+ useSelectedContext : throwInvalidHookError ,
2071
2123
useEffect : throwInvalidHookError ,
2072
2124
useImperativeHandle : throwInvalidHookError ,
2073
2125
useLayoutEffect : throwInvalidHookError ,
@@ -2093,6 +2145,7 @@ const HooksDispatcherOnMount: Dispatcher = {
2093
2145
2094
2146
useCallback : mountCallback ,
2095
2147
useContext : readContext ,
2148
+ useSelectedContext : mountSelectedContext ,
2096
2149
useEffect : mountEffect ,
2097
2150
useImperativeHandle : mountImperativeHandle ,
2098
2151
useLayoutEffect : mountLayoutEffect ,
@@ -2118,6 +2171,7 @@ const HooksDispatcherOnUpdate: Dispatcher = {
2118
2171
2119
2172
useCallback : updateCallback ,
2120
2173
useContext : readContext ,
2174
+ useSelectedContext : updateSelectedContext ,
2121
2175
useEffect : updateEffect ,
2122
2176
useImperativeHandle : updateImperativeHandle ,
2123
2177
useLayoutEffect : updateLayoutEffect ,
@@ -2143,6 +2197,7 @@ const HooksDispatcherOnRerender: Dispatcher = {
2143
2197
2144
2198
useCallback : updateCallback ,
2145
2199
useContext : readContext ,
2200
+ useSelectedContext : updateSelectedContext ,
2146
2201
useEffect : updateEffect ,
2147
2202
useImperativeHandle : updateImperativeHandle ,
2148
2203
useLayoutEffect : updateLayoutEffect ,
@@ -2211,6 +2266,21 @@ if (__DEV__) {
2211
2266
mountHookTypesDev ( ) ;
2212
2267
return readContext ( context , observedBits ) ;
2213
2268
} ,
2269
+ useSelectedContext< C , S > (
2270
+ context: ReactContext< C > ,
2271
+ selector: C => S ,
2272
+ isEqual : ( ( S , S ) => boolean ) | void ,
2273
+ ) : S {
2274
+ currentHookNameInDev = 'useSelectedContext' ;
2275
+ mountHookTypesDev ( ) ;
2276
+ const prevDispatcher = ReactCurrentDispatcher . current ;
2277
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnMountInDEV ;
2278
+ try {
2279
+ return mountSelectedContext ( context , selector , isEqual ) ;
2280
+ } finally {
2281
+ ReactCurrentDispatcher . current = prevDispatcher ;
2282
+ }
2283
+ } ,
2214
2284
useEffect (
2215
2285
create : ( ) => ( ( ) => void ) | void ,
2216
2286
deps : Array < mixed > | void | null,
@@ -2345,6 +2415,21 @@ if (__DEV__) {
2345
2415
updateHookTypesDev ( ) ;
2346
2416
return readContext ( context , observedBits ) ;
2347
2417
} ,
2418
+ useSelectedContext< C , S > (
2419
+ context: ReactContext< C > ,
2420
+ selector: C => S ,
2421
+ isEqual : ( ( S , S ) => boolean ) | void ,
2422
+ ) : S {
2423
+ currentHookNameInDev = 'useSelectedContext' ;
2424
+ updateHookTypesDev ( ) ;
2425
+ const prevDispatcher = ReactCurrentDispatcher . current ;
2426
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnMountInDEV ;
2427
+ try {
2428
+ return mountSelectedContext ( context , selector , isEqual ) ;
2429
+ } finally {
2430
+ ReactCurrentDispatcher . current = prevDispatcher ;
2431
+ }
2432
+ } ,
2348
2433
useEffect (
2349
2434
create : ( ) => ( ( ) => void ) | void ,
2350
2435
deps : Array < mixed > | void | null,
@@ -2475,6 +2560,21 @@ if (__DEV__) {
2475
2560
updateHookTypesDev ( ) ;
2476
2561
return readContext ( context , observedBits ) ;
2477
2562
} ,
2563
+ useSelectedContext< C , S > (
2564
+ context: ReactContext< C > ,
2565
+ selector: C => S ,
2566
+ isEqual : ( ( S , S ) => boolean ) | void ,
2567
+ ) : S {
2568
+ currentHookNameInDev = 'useSelectedContext' ;
2569
+ updateHookTypesDev ( ) ;
2570
+ const prevDispatcher = ReactCurrentDispatcher . current ;
2571
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnUpdateInDEV ;
2572
+ try {
2573
+ return updateSelectedContext ( context , selector , isEqual ) ;
2574
+ } finally {
2575
+ ReactCurrentDispatcher . current = prevDispatcher ;
2576
+ }
2577
+ } ,
2478
2578
useEffect (
2479
2579
create : ( ) => ( ( ) => void ) | void ,
2480
2580
deps : Array < mixed > | void | null,
@@ -2606,6 +2706,21 @@ if (__DEV__) {
2606
2706
updateHookTypesDev ( ) ;
2607
2707
return readContext ( context , observedBits ) ;
2608
2708
} ,
2709
+ useSelectedContext< C , S > (
2710
+ context: ReactContext< C > ,
2711
+ selector: C => S ,
2712
+ isEqual : ( ( S , S ) => boolean ) | void ,
2713
+ ) : S {
2714
+ currentHookNameInDev = 'useSelectedContext' ;
2715
+ updateHookTypesDev ( ) ;
2716
+ const prevDispatcher = ReactCurrentDispatcher . current ;
2717
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnRerenderInDEV ;
2718
+ try {
2719
+ return updateSelectedContext ( context , selector , isEqual ) ;
2720
+ } finally {
2721
+ ReactCurrentDispatcher . current = prevDispatcher ;
2722
+ }
2723
+ } ,
2609
2724
useEffect (
2610
2725
create : ( ) => ( ( ) => void ) | void ,
2611
2726
deps : Array < mixed > | void | null,
@@ -2739,6 +2854,22 @@ if (__DEV__) {
2739
2854
mountHookTypesDev ( ) ;
2740
2855
return readContext ( context , observedBits ) ;
2741
2856
} ,
2857
+ useSelectedContext< C , S > (
2858
+ context: ReactContext< C > ,
2859
+ selector: C => S ,
2860
+ isEqual : ( ( S , S ) => boolean ) | void ,
2861
+ ) : S {
2862
+ currentHookNameInDev = 'useSelectedContext' ;
2863
+ warnInvalidHookAccess ( ) ;
2864
+ mountHookTypesDev ( ) ;
2865
+ const prevDispatcher = ReactCurrentDispatcher . current ;
2866
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnMountInDEV ;
2867
+ try {
2868
+ return mountSelectedContext ( context , selector , isEqual ) ;
2869
+ } finally {
2870
+ ReactCurrentDispatcher . current = prevDispatcher ;
2871
+ }
2872
+ } ,
2742
2873
useEffect (
2743
2874
create : ( ) => ( ( ) => void ) | void ,
2744
2875
deps : Array < mixed > | void | null,
@@ -2884,6 +3015,22 @@ if (__DEV__) {
2884
3015
updateHookTypesDev ( ) ;
2885
3016
return readContext ( context , observedBits ) ;
2886
3017
} ,
3018
+ useSelectedContext< C , S > (
3019
+ context: ReactContext< C > ,
3020
+ selector: C => S ,
3021
+ isEqual : ( ( S , S ) => boolean ) | void ,
3022
+ ) : S {
3023
+ currentHookNameInDev = 'useSelectedContext' ;
3024
+ warnInvalidHookAccess ( ) ;
3025
+ updateHookTypesDev ( ) ;
3026
+ const prevDispatcher = ReactCurrentDispatcher . current ;
3027
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnUpdateInDEV ;
3028
+ try {
3029
+ return updateSelectedContext ( context , selector , isEqual ) ;
3030
+ } finally {
3031
+ ReactCurrentDispatcher . current = prevDispatcher ;
3032
+ }
3033
+ } ,
2887
3034
useEffect (
2888
3035
create : ( ) => ( ( ) => void ) | void ,
2889
3036
deps : Array < mixed > | void | null,
@@ -3030,6 +3177,22 @@ if (__DEV__) {
3030
3177
updateHookTypesDev ( ) ;
3031
3178
return readContext ( context , observedBits ) ;
3032
3179
} ,
3180
+ useSelectedContext< C , S > (
3181
+ context: ReactContext< C > ,
3182
+ selector: C => S ,
3183
+ isEqual : ( ( S , S ) => boolean ) | void ,
3184
+ ) : S {
3185
+ currentHookNameInDev = 'useSelectedContext' ;
3186
+ warnInvalidHookAccess ( ) ;
3187
+ updateHookTypesDev ( ) ;
3188
+ const prevDispatcher = ReactCurrentDispatcher . current ;
3189
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnUpdateInDEV ;
3190
+ try {
3191
+ return updateSelectedContext ( context , selector , isEqual ) ;
3192
+ } finally {
3193
+ ReactCurrentDispatcher . current = prevDispatcher ;
3194
+ }
3195
+ } ,
3033
3196
useEffect (
3034
3197
create : ( ) => ( ( ) => void ) | void ,
3035
3198
deps : Array < mixed > | void | null,
0 commit comments