@@ -16,7 +16,12 @@ import type {
16
16
Usable ,
17
17
Thenable ,
18
18
} from 'shared/ReactTypes' ;
19
- import type { Fiber , Dispatcher , HookType } from './ReactInternalTypes' ;
19
+ import type {
20
+ Fiber ,
21
+ Dispatcher ,
22
+ HookType ,
23
+ MemoCache ,
24
+ } from './ReactInternalTypes' ;
20
25
import type { Lanes , Lane } from './ReactFiberLane.new' ;
21
26
import type { HookFlags } from './ReactHookEffectTags' ;
22
27
import type { FiberRoot } from './ReactInternalTypes' ;
@@ -177,6 +182,8 @@ type StoreConsistencyCheck<T> = {
177
182
export type FunctionComponentUpdateQueue = {
178
183
lastEffect : Effect | null ,
179
184
stores : Array < StoreConsistencyCheck < any >> | null ,
185
+ // NOTE: optional, only set when enableUseMemoCacheHook is enabled
186
+ memoCache ?: MemoCache | null ,
180
187
} ;
181
188
182
189
type BasicStateAction < S > = ( S => S ) | S ;
@@ -710,10 +717,23 @@ function updateWorkInProgressHook(): Hook {
710
717
return workInProgressHook ;
711
718
}
712
719
713
- function createFunctionComponentUpdateQueue ( ) : FunctionComponentUpdateQueue {
714
- return {
715
- lastEffect : null ,
716
- stores : null ,
720
+ // NOTE: defining two versions of this function to avoid size impact when this feature is disabled.
721
+ // Previously this function was inlined, the additional `memoCache` property makes it not inlined.
722
+ let createFunctionComponentUpdateQueue : ( ) => FunctionComponentUpdateQueue ;
723
+ if ( enableUseMemoCacheHook ) {
724
+ createFunctionComponentUpdateQueue = ( ) => {
725
+ return {
726
+ lastEffect : null ,
727
+ stores : null ,
728
+ memoCache : null ,
729
+ } ;
730
+ } ;
731
+ } else {
732
+ createFunctionComponentUpdateQueue = ( ) => {
733
+ return {
734
+ lastEffect : null ,
735
+ stores : null ,
736
+ } ;
717
737
} ;
718
738
}
719
739
@@ -787,7 +807,59 @@ function use<T>(usable: Usable<T>): T {
787
807
}
788
808
789
809
function useMemoCache ( size : number ) : Array < any > {
790
- throw new Error ( 'Not implemented.' ) ;
810
+ let memoCache = null ;
811
+ // Fast-path, load memo cache from wip fiber if already prepared
812
+ let updateQueue : FunctionComponentUpdateQueue | null = ( currentlyRenderingFiber . updateQueue : any ) ;
813
+ if ( updateQueue !== null ) {
814
+ memoCache = updateQueue . memoCache ;
815
+ }
816
+ // Otherwise clone from the current fiber
817
+ // TODO: not sure how to access the current fiber here other than going through
818
+ // currentlyRenderingFiber.alternate
819
+ if ( memoCache == null ) {
820
+ const current : Fiber | null = currentlyRenderingFiber . alternate ;
821
+ if ( current !== null ) {
822
+ const currentUpdateQueue : FunctionComponentUpdateQueue | null = ( current . updateQueue : any ) ;
823
+ if ( currentUpdateQueue !== null ) {
824
+ const currentMemoCache : ?MemoCache = currentUpdateQueue . memoCache ;
825
+ if ( currentMemoCache != null ) {
826
+ memoCache = {
827
+ data : currentMemoCache . data . map ( array => array . slice ( ) ) ,
828
+ index : 0 ,
829
+ } ;
830
+ }
831
+ }
832
+ }
833
+ }
834
+ // Finally fall back to allocating a fresh instance of the cache
835
+ if (memoCache == null) {
836
+ memoCache = {
837
+ data : [ ] ,
838
+ index : 0 ,
839
+ } ;
840
+ }
841
+ if (updateQueue === null) {
842
+ updateQueue = createFunctionComponentUpdateQueue ( ) ;
843
+ currentlyRenderingFiber . updateQueue = updateQueue ;
844
+ }
845
+ updateQueue.memoCache = memoCache;
846
+
847
+ let data = memoCache.data[memoCache.index];
848
+ if (data === undefined) {
849
+ data = memoCache . data [ memoCache . index ] = new Array ( size ) ;
850
+ } else if (data.length !== size) {
851
+ // TODO: consider warning or throwing here
852
+ if ( __DEV__ ) {
853
+ console . error (
854
+ 'Expected a constant size argument for each invocation of useMemoCache. ' +
855
+ 'The previous cache was allocated with size %s but size %s was requested.' ,
856
+ data . length ,
857
+ size ,
858
+ ) ;
859
+ }
860
+ }
861
+ memoCache . index ++ ;
862
+ return data ;
791
863
}
792
864
793
865
function basicStateReducer < S > (state: S, action: BasicStateAction< S > ): S {
0 commit comments