@@ -23,7 +23,8 @@ import type {
23
23
OffscreenProps ,
24
24
OffscreenState ,
25
25
} from './ReactFiberOffscreenComponent' ;
26
- import type { CacheInstance } from './ReactFiberCacheComponent' ;
26
+ import type { CacheInstance , Cache } from './ReactFiberCacheComponent' ;
27
+ import type { UpdateQueue } from './ReactUpdateQueue.new' ;
27
28
28
29
import checkPropTypes from 'shared/checkPropTypes' ;
29
30
@@ -671,9 +672,11 @@ function updateCacheComponent(
671
672
? CacheContext . _currentValue
672
673
: CacheContext . _currentValue2 ;
673
674
674
- let ownCacheInstance : CacheInstance | null = null ;
675
+ let cacheInstance : CacheInstance | null = null ;
675
676
if ( current === null ) {
676
677
// This is a newly mounted component. Request a fresh cache.
678
+ // TODO: Fast path when parent cache component is also a new mount? We can
679
+ // check `parentCacheInstance.provider.alternate`.
677
680
const root = getWorkInProgressRoot ( ) ;
678
681
invariant (
679
682
root !== null ,
@@ -684,62 +687,74 @@ function updateCacheComponent(
684
687
// This may be the same as the parent cache, like if the current render
685
688
// spawned from a previous render that already committed. Otherwise, this
686
689
// is the root of a cache consistency boundary.
690
+ let initialState ;
687
691
if ( freshCache !== parentCacheInstance . cache ) {
688
- ownCacheInstance = {
692
+ cacheInstance = {
689
693
cache : freshCache ,
690
694
provider : workInProgress ,
691
695
} ;
692
- pushProvider ( workInProgress , CacheContext , ownCacheInstance ) ;
696
+ initialState = {
697
+ cache : freshCache ,
698
+ } ;
699
+ pushProvider ( workInProgress , CacheContext , cacheInstance ) ;
693
700
// No need to propagate the refresh, because this is a new tree.
694
701
} else {
695
702
// Use the parent cache
696
- ownCacheInstance = null ;
703
+ cacheInstance = null ;
704
+ initialState = {
705
+ cache : null ,
706
+ } ;
697
707
}
708
+ // Initialize an update queue. We use this for refreshes.
709
+ workInProgress . memoizedState = initialState ;
710
+ initializeUpdateQueue ( workInProgress ) ;
698
711
} else {
699
712
// This component already mounted.
700
713
if ( includesSomeLane ( renderLanes , updateLanes ) ) {
701
- // A refresh was scheduled.
702
- const root = getWorkInProgressRoot ( ) ;
703
- invariant (
704
- root !== null ,
705
- 'Expected a work-in-progress root. This is a bug in React. Please ' +
706
- 'file an issue.' ,
707
- ) ;
708
- const freshCache = requestFreshCache ( root , renderLanes ) ;
709
- if (
710
- parentCacheInstance === null ||
711
- freshCache !== parentCacheInstance . cache
712
- ) {
713
- ownCacheInstance = {
714
- cache : freshCache ,
714
+ // An refresh was scheduled. If it was an refresh on this fiber, then we
715
+ // will have an update in the queue. Otherwise, it must have been an
716
+ // update on a parent, propagated via context.
717
+ cloneUpdateQueue ( current , workInProgress ) ;
718
+ processUpdateQueue ( workInProgress , null , null , renderLanes ) ;
719
+ const prevCache : Cache | null = current . memoizedState . cache ;
720
+ const nextCache : Cache | null = workInProgress . memoizedState . cache ;
721
+
722
+ if ( nextCache !== prevCache && nextCache !== null ) {
723
+ // Received a refresh.
724
+ cacheInstance = {
725
+ cache : nextCache ,
715
726
provider : workInProgress ,
716
727
} ;
717
- pushProvider ( workInProgress , CacheContext , ownCacheInstance ) ;
728
+ pushProvider ( workInProgress , CacheContext , cacheInstance ) ;
718
729
// Refreshes propagate through the entire subtree. The refreshed cache
719
730
// will override nested caches.
720
731
propagateCacheRefresh ( workInProgress , renderLanes ) ;
721
732
} else {
722
- // The fresh cache is the same as the parent cache.
723
- ownCacheInstance = null ;
733
+ // A parent cache boundary refreshed. So we can use the cache context.
734
+ cacheInstance = null ;
735
+
736
+ // If the update queue is empty, disconnect the old cache from the tree
737
+ // so it can be garbage collected.
738
+ if ( workInProgress . lanes === NoLanes ) {
739
+ const updateQueue : UpdateQueue < any > = (workInProgress.updateQueue: any);
740
+ workInProgress.memoizedState = updateQueue.baseState = { cache : null } ;
741
+ }
724
742
}
725
743
} else {
726
744
// Reuse the memoized cache.
727
- const prevCacheInstance : CacheInstance | null = current . memoizedState ;
728
- if ( prevCacheInstance !== null ) {
729
- ownCacheInstance = prevCacheInstance ;
745
+ cacheInstance = current . stateNode ;
746
+ if ( cacheInstance !== null ) {
730
747
// There was no refresh, so no need to propagate to nested boundaries.
731
- pushProvider ( workInProgress , CacheContext , ownCacheInstance ) ;
732
- } else {
733
- ownCacheInstance = null ;
748
+ pushProvider ( workInProgress , CacheContext , cacheInstance ) ;
734
749
}
735
750
}
736
751
}
737
752
738
- // If this CacheComponent is the root of its tree, then `memoizedState ` will
739
- // point to a cache object . Otherwise, a null state indicates that this
753
+ // If this CacheComponent is the root of its tree, then `stateNode ` will
754
+ // point to a cache instance . Otherwise, a null instance indicates that this
740
755
// CacheComponent inherits from a parent boundary. We can use this to infer
741
756
// whether to push/pop the cache context.
742
- workInProgress . memoizedState = ownCacheInstance ;
757
+ workInProgress . stateNode = cacheInstance ;
743
758
744
759
const nextChildren = workInProgress . pendingProps . children ;
745
760
reconcileChildren ( current , workInProgress , nextChildren , renderLanes ) ;
@@ -3349,11 +3364,11 @@ function beginWork(
3349
3364
}
3350
3365
case CacheComponent: {
3351
3366
if ( enableCache ) {
3352
- const ownCacheInstance : CacheInstance | null =
3353
- workInProgress . memoizedState ;
3367
+ const ownCacheInstance : CacheInstance | null = current . stateNode ;
3354
3368
if ( ownCacheInstance !== null ) {
3355
3369
pushProvider ( workInProgress , CacheContext , ownCacheInstance ) ;
3356
3370
}
3371
+ workInProgress . stateNode = ownCacheInstance ;
3357
3372
}
3358
3373
break ;
3359
3374
}
0 commit comments