@@ -12,6 +12,7 @@ import type {
1212  Fiber , 
1313  ContextDependency , 
1414  Dependencies , 
15+   ContextDependencyWithCompare , 
1516}  from  './ReactInternalTypes' ; 
1617import  type  { StackCursor }  from  './ReactFiberStack' ; 
1718import  type  { Lanes }  from  './ReactFiberLane' ; 
@@ -72,7 +73,10 @@ if (__DEV__) {
7273} 
7374
7475let currentlyRenderingFiber: Fiber | null = null;
75- let lastContextDependency: ContextDependency< mixed ,  mixed >  | null = null;
76+ let lastContextDependency:
77+   | ContextDependency< mixed > 
78+   | ContextDependencyWithCompare< mixed ,  mixed > 
79+   | null = null;
7680let lastFullyObservedContext: ReactContext< any >  | null = null;
7781
7882let isDisallowedContextReadInDEV: boolean = false;
@@ -403,19 +407,21 @@ function propagateContextChanges<T>(
403407          const  context : ReactContext < T >  =  contexts [ i ] ; 
404408          // Check if the context matches. 
405409          if  ( dependency . context  ===  context )  { 
406-             const  compare  =  dependency . compare ; 
407-             if  ( enableContextProfiling  &&  compare  !=  null )  { 
408-               const  newValue =  isPrimaryRenderer 
409-                 ? dependency . context . _currentValue 
410-                 : dependency . context . _currentValue2 ; 
411-               if  ( 
412-                 ! checkIfComparedContextValuesChanged ( 
413-                   dependency . lastComparedValue , 
414-                   compare ( newValue ) , 
415-                 ) 
416-               )  { 
417-                 // Compared value hasn't changed. Bail out early. 
418-                 continue  findContext ; 
410+             if  ( enableContextProfiling )  { 
411+               const  compare  =  dependency . compare ; 
412+               if  ( compare  !=  null )  { 
413+                 const  newValue  =  isPrimaryRenderer 
414+                   ? dependency . context . _currentValue 
415+                   : dependency . context . _currentValue2 ; 
416+                 if  ( 
417+                   ! checkIfComparedContextValuesChanged ( 
418+                     dependency . lastComparedValue , 
419+                     compare ( newValue ) , 
420+                   ) 
421+                 )  { 
422+                   // Compared value hasn't changed. Bail out early. 
423+                   continue  findContext; 
424+                 } 
419425              } 
420426            } 
421427            // Match! Schedule an update on this fiber. 
@@ -746,13 +752,17 @@ export function prepareToReadContext(
746752
747753export function readContextAndCompare< C > (
748754  context: ReactContext< C > ,
749-   compare: void |  (C =>  mixed ) , 
755+   compare: (C =>  mixed )   |   null , 
750756) : C  { 
751757  if  ( ! enableLazyContextPropagation ) { 
752758    return  readContext ( context ) ; 
753759  } 
754760
755-   return readContextForConsumer(currentlyRenderingFiber, context, compare);
761+   return readContextForConsumer_withCompare(
762+     currentlyRenderingFiber,
763+     context,
764+     compare,
765+   );
756766} 
757767
758768export  function  readContext < T > (context: ReactContext< T > ): T { 
@@ -782,12 +792,12 @@ export function readContextDuringReconciliation<T>(
782792  return readContextForConsumer(consumer, context);
783793} 
784794
785- type  ContextCompare < C ,  S >  = C =>  S ; 
795+ type  ContextCompare < C ,  V >  = C =>  V   |   null ; 
786796
787- function  readContextForConsumer < C ,  S > (
797+ function  readContextForConsumer_withCompare < C ,  S > (
788798  consumer: Fiber | null,
789799  context: ReactContext< C > ,
790-   compare?: void |  (C =>  S ) , 
800+   compare:  (C =>  S )   |   null , 
791801) : C  { 
792802  const  value  =  isPrimaryRenderer 
793803    ? context . _currentValue 
@@ -800,7 +810,7 @@ function readContextForConsumer<C, S>(
800810      context : ( ( context : any ) : ReactContext < mixed > ) , 
801811      memoizedValue : value , 
802812      next : null , 
803-       compare : ( ( compare : any ) : ContextCompare < mixed ,  mixed >   |  null ) , 
813+       compare : compare  ?  ( ( compare : any ) : ContextCompare < mixed ,  mixed > )  :  null , 
804814      lastComparedValue : compare  !=  null  ? compare ( value )  : null , 
805815    } ; 
806816
@@ -830,3 +840,47 @@ function readContextForConsumer<C, S>(
830840  } 
831841  return  value ; 
832842} 
843+ 
844+ function  readContextForConsumer < C > (
845+   consumer: Fiber | null,
846+   context: ReactContext< C > ,
847+ ): C { 
848+   const  value  =  isPrimaryRenderer 
849+     ? context . _currentValue 
850+     : context . _currentValue2 ; 
851+ 
852+   if  ( lastFullyObservedContext  ===  context ) { 
853+     // Nothing to do. We already observe everything in this context. 
854+   }  else { 
855+     const  contextItem  =  { 
856+       context : ( ( context : any ) : ReactContext < mixed > ) , 
857+       memoizedValue : value , 
858+       next : null , 
859+     } ; 
860+ 
861+     if  ( lastContextDependency  ===  null ) { 
862+       if  ( consumer  ===  null ) { 
863+         throw  new  Error ( 
864+           'Context can only be read while React is rendering. '  + 
865+             'In classes, you can read it in the render method or getDerivedStateFromProps. '  + 
866+             'In function components, you can read it directly in the function body, but not '  + 
867+             'inside Hooks like useReducer() or useMemo().' , 
868+         ) ; 
869+       } 
870+ 
871+       // This is the first dependency for this component. Create a new list.
872+       lastContextDependency = contextItem;
873+       consumer.dependencies = { 
874+         lanes : NoLanes , 
875+         firstContext : contextItem , 
876+       } ;
877+       if (enableLazyContextPropagation) { 
878+         consumer . flags  |=  NeedsPropagation ; 
879+       } 
880+     }  else  { 
881+       // Append a new context item. 
882+       lastContextDependency  =  lastContextDependency . next  =  contextItem ; 
883+     } 
884+   } 
885+   return  value ; 
886+ } 
0 commit comments