@@ -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 ,
@@ -2069,6 +2120,7 @@ export const ContextOnlyDispatcher: Dispatcher = {
2069
2120
2070
2121
useCallback : throwInvalidHookError ,
2071
2122
useContext : throwInvalidHookError ,
2123
+ useSelectedContext : throwInvalidHookError ,
2072
2124
useEffect : throwInvalidHookError ,
2073
2125
useImperativeHandle : throwInvalidHookError ,
2074
2126
useLayoutEffect : throwInvalidHookError ,
@@ -2094,6 +2146,7 @@ const HooksDispatcherOnMount: Dispatcher = {
2094
2146
2095
2147
useCallback : mountCallback ,
2096
2148
useContext : readContext ,
2149
+ useSelectedContext : mountSelectedContext ,
2097
2150
useEffect : mountEffect ,
2098
2151
useImperativeHandle : mountImperativeHandle ,
2099
2152
useLayoutEffect : mountLayoutEffect ,
@@ -2119,6 +2172,7 @@ const HooksDispatcherOnUpdate: Dispatcher = {
2119
2172
2120
2173
useCallback : updateCallback ,
2121
2174
useContext : readContext ,
2175
+ useSelectedContext : updateSelectedContext ,
2122
2176
useEffect : updateEffect ,
2123
2177
useImperativeHandle : updateImperativeHandle ,
2124
2178
useLayoutEffect : updateLayoutEffect ,
@@ -2144,6 +2198,7 @@ const HooksDispatcherOnRerender: Dispatcher = {
2144
2198
2145
2199
useCallback : updateCallback ,
2146
2200
useContext : readContext ,
2201
+ useSelectedContext : updateSelectedContext ,
2147
2202
useEffect : updateEffect ,
2148
2203
useImperativeHandle : updateImperativeHandle ,
2149
2204
useLayoutEffect : updateLayoutEffect ,
@@ -2212,6 +2267,21 @@ if (__DEV__) {
2212
2267
mountHookTypesDev ( ) ;
2213
2268
return readContext ( context , observedBits ) ;
2214
2269
} ,
2270
+ useSelectedContext< C , S > (
2271
+ context: ReactContext< C > ,
2272
+ selector: C => S ,
2273
+ isEqual : ( ( S , S ) => boolean ) | void ,
2274
+ ) : S {
2275
+ currentHookNameInDev = 'useSelectedContext' ;
2276
+ mountHookTypesDev ( ) ;
2277
+ const prevDispatcher = ReactCurrentDispatcher . current ;
2278
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnMountInDEV ;
2279
+ try {
2280
+ return mountSelectedContext ( context , selector , isEqual ) ;
2281
+ } finally {
2282
+ ReactCurrentDispatcher . current = prevDispatcher ;
2283
+ }
2284
+ } ,
2215
2285
useEffect (
2216
2286
create : ( ) => ( ( ) => void ) | void ,
2217
2287
deps : Array < mixed > | void | null,
@@ -2346,6 +2416,21 @@ if (__DEV__) {
2346
2416
updateHookTypesDev ( ) ;
2347
2417
return readContext ( context , observedBits ) ;
2348
2418
} ,
2419
+ useSelectedContext< C , S > (
2420
+ context: ReactContext< C > ,
2421
+ selector: C => S ,
2422
+ isEqual : ( ( S , S ) => boolean ) | void ,
2423
+ ) : S {
2424
+ currentHookNameInDev = 'useSelectedContext' ;
2425
+ updateHookTypesDev ( ) ;
2426
+ const prevDispatcher = ReactCurrentDispatcher . current ;
2427
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnMountInDEV ;
2428
+ try {
2429
+ return mountSelectedContext ( context , selector , isEqual ) ;
2430
+ } finally {
2431
+ ReactCurrentDispatcher . current = prevDispatcher ;
2432
+ }
2433
+ } ,
2349
2434
useEffect (
2350
2435
create : ( ) => ( ( ) => void ) | void ,
2351
2436
deps : Array < mixed > | void | null,
@@ -2476,6 +2561,21 @@ if (__DEV__) {
2476
2561
updateHookTypesDev ( ) ;
2477
2562
return readContext ( context , observedBits ) ;
2478
2563
} ,
2564
+ useSelectedContext< C , S > (
2565
+ context: ReactContext< C > ,
2566
+ selector: C => S ,
2567
+ isEqual : ( ( S , S ) => boolean ) | void ,
2568
+ ) : S {
2569
+ currentHookNameInDev = 'useSelectedContext' ;
2570
+ updateHookTypesDev ( ) ;
2571
+ const prevDispatcher = ReactCurrentDispatcher . current ;
2572
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnUpdateInDEV ;
2573
+ try {
2574
+ return updateSelectedContext ( context , selector , isEqual ) ;
2575
+ } finally {
2576
+ ReactCurrentDispatcher . current = prevDispatcher ;
2577
+ }
2578
+ } ,
2479
2579
useEffect (
2480
2580
create : ( ) => ( ( ) => void ) | void ,
2481
2581
deps : Array < mixed > | void | null,
@@ -2607,6 +2707,21 @@ if (__DEV__) {
2607
2707
updateHookTypesDev ( ) ;
2608
2708
return readContext ( context , observedBits ) ;
2609
2709
} ,
2710
+ useSelectedContext< C , S > (
2711
+ context: ReactContext< C > ,
2712
+ selector: C => S ,
2713
+ isEqual : ( ( S , S ) => boolean ) | void ,
2714
+ ) : S {
2715
+ currentHookNameInDev = 'useSelectedContext' ;
2716
+ updateHookTypesDev ( ) ;
2717
+ const prevDispatcher = ReactCurrentDispatcher . current ;
2718
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnRerenderInDEV ;
2719
+ try {
2720
+ return updateSelectedContext ( context , selector , isEqual ) ;
2721
+ } finally {
2722
+ ReactCurrentDispatcher . current = prevDispatcher ;
2723
+ }
2724
+ } ,
2610
2725
useEffect (
2611
2726
create : ( ) => ( ( ) => void ) | void ,
2612
2727
deps : Array < mixed > | void | null,
@@ -2740,6 +2855,22 @@ if (__DEV__) {
2740
2855
mountHookTypesDev ( ) ;
2741
2856
return readContext ( context , observedBits ) ;
2742
2857
} ,
2858
+ useSelectedContext< C , S > (
2859
+ context: ReactContext< C > ,
2860
+ selector: C => S ,
2861
+ isEqual : ( ( S , S ) => boolean ) | void ,
2862
+ ) : S {
2863
+ currentHookNameInDev = 'useSelectedContext' ;
2864
+ warnInvalidHookAccess ( ) ;
2865
+ mountHookTypesDev ( ) ;
2866
+ const prevDispatcher = ReactCurrentDispatcher . current ;
2867
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnMountInDEV ;
2868
+ try {
2869
+ return mountSelectedContext ( context , selector , isEqual ) ;
2870
+ } finally {
2871
+ ReactCurrentDispatcher . current = prevDispatcher ;
2872
+ }
2873
+ } ,
2743
2874
useEffect (
2744
2875
create : ( ) => ( ( ) => void ) | void ,
2745
2876
deps : Array < mixed > | void | null,
@@ -2885,6 +3016,22 @@ if (__DEV__) {
2885
3016
updateHookTypesDev ( ) ;
2886
3017
return readContext ( context , observedBits ) ;
2887
3018
} ,
3019
+ useSelectedContext< C , S > (
3020
+ context: ReactContext< C > ,
3021
+ selector: C => S ,
3022
+ isEqual : ( ( S , S ) => boolean ) | void ,
3023
+ ) : S {
3024
+ currentHookNameInDev = 'useSelectedContext' ;
3025
+ warnInvalidHookAccess ( ) ;
3026
+ updateHookTypesDev ( ) ;
3027
+ const prevDispatcher = ReactCurrentDispatcher . current ;
3028
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnUpdateInDEV ;
3029
+ try {
3030
+ return updateSelectedContext ( context , selector , isEqual ) ;
3031
+ } finally {
3032
+ ReactCurrentDispatcher . current = prevDispatcher ;
3033
+ }
3034
+ } ,
2888
3035
useEffect (
2889
3036
create : ( ) => ( ( ) => void ) | void ,
2890
3037
deps : Array < mixed > | void | null,
@@ -3031,6 +3178,22 @@ if (__DEV__) {
3031
3178
updateHookTypesDev ( ) ;
3032
3179
return readContext ( context , observedBits ) ;
3033
3180
} ,
3181
+ useSelectedContext< C , S > (
3182
+ context: ReactContext< C > ,
3183
+ selector: C => S ,
3184
+ isEqual : ( ( S , S ) => boolean ) | void ,
3185
+ ) : S {
3186
+ currentHookNameInDev = 'useSelectedContext' ;
3187
+ warnInvalidHookAccess ( ) ;
3188
+ updateHookTypesDev ( ) ;
3189
+ const prevDispatcher = ReactCurrentDispatcher . current ;
3190
+ ReactCurrentDispatcher . current = InvalidNestedHooksDispatcherOnUpdateInDEV ;
3191
+ try {
3192
+ return updateSelectedContext ( context , selector , isEqual ) ;
3193
+ } finally {
3194
+ ReactCurrentDispatcher . current = prevDispatcher ;
3195
+ }
3196
+ } ,
3034
3197
useEffect (
3035
3198
create : ( ) => ( ( ) => void ) | void ,
3036
3199
deps : Array < mixed > | void | null,
0 commit comments