90
ShouldCapture,
91
ForceClientRender,
92
Passive,
93
+ DidDefer,
94
} from './ReactFiberFlags';
95
import ReactSharedInternals from 'shared/ReactSharedInternals';
96
import {
258
renderDidSuspendDelayIfPossible,
259
markSkippedUpdateLanes,
260
getWorkInProgressRoot,
261
+ peekDeferredLane,
262
} from './ReactFiberWorkLoop';
263
import {enqueueConcurrentRenderForLane} from './ReactFiberConcurrentUpdates';
264
import {pushCacheProvider, CacheContext} from './ReactFiberCacheComponent';
2230
);
2231
}
2232
2231
-function getRemainingWorkInPrimaryTree(current: Fiber, renderLanes: Lanes) {
2232
- // TODO: Should not remove render lanes that were pinged during this render
2233
- return removeLanes(current.childLanes, renderLanes);
2233
+function getRemainingWorkInPrimaryTree(
2234
+ current: Fiber | null,
2235
+ primaryTreeDidDefer: boolean,
2236
+ renderLanes: Lanes,
2237
+) {
2238
+ let remainingLanes =
2239
+ current !== null ? removeLanes(current.childLanes, renderLanes) : NoLanes;
2240
+ if (primaryTreeDidDefer) {
2241
+ // A useDeferredValue hook spawned a deferred task inside the primary tree.
2242
+ // Ensure that we retry this component at the deferred priority.
2243
+ // TODO: We could make this a per-subtree value instead of a global one.
2244
+ // Would need to track it on the context stack somehow, similar to what
2245
+ // we'd have to do for resumable contexts.
2246
+ remainingLanes = mergeLanes(remainingLanes, peekDeferredLane());
2247
+ }
2248
+ return remainingLanes;
2249
}
2250
2251
function updateSuspenseComponent(
2274
workInProgress.flags &= ~DidCapture;
2275
}
2276
2277
+ // Check if the primary children spawned a deferred task (useDeferredValue)
2278
+ // during the first pass.
2279
+ const didPrimaryChildrenDefer = (workInProgress.flags & DidDefer) !== NoFlags;
2280
+ workInProgress.flags &= ~DidDefer;
2281
+
2282
// OK, the next part is confusing. We're about to reconcile the Suspense
2283
// boundary's children. This involves some custom reconciliation logic. Two
2284
// main reasons this is so complicated.
2349
const primaryChildFragment: Fiber = (workInProgress.child: any);
2350
primaryChildFragment.memoizedState =
2351
mountSuspenseOffscreenState(renderLanes);
2352
+ primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(
2353
+ current,
2354
+ didPrimaryChildrenDefer,
2355
+ renderLanes,
2356
+ );
2357
workInProgress.memoizedState = SUSPENDED_MARKER;
2358
if (enableTransitionTracing) {
2359
const currentTransitions = getPendingTransitions();
2393
const primaryChildFragment: Fiber = (workInProgress.child: any);
2394
primaryChildFragment.memoizedState =
2395
mountSuspenseOffscreenState(renderLanes);
2396
+ primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(
2397
+ current,
2398
+ didPrimaryChildrenDefer,
2399
+ renderLanes,
2400
+ );
2401
workInProgress.memoizedState = SUSPENDED_MARKER;
2402
2403
// TODO: Transition Tracing is not yet implemented for CPU Suspense.
2432
current,
2433
workInProgress,
2434
didSuspend,
2435
+ didPrimaryChildrenDefer,
2436
nextProps,
2437
dehydrated,
2438
prevState,
2495
}
2496
primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(
2497
current,
2498
+ didPrimaryChildrenDefer,
2499
renderLanes,
2500
);
2501
workInProgress.memoizedState = SUSPENDED_MARKER;
2866
current: Fiber,
2867
workInProgress: Fiber,
2868
didSuspend: boolean,
2869
+ didPrimaryChildrenDefer: boolean,
2870
nextProps: any,
2871
suspenseInstance: SuspenseInstance,
2872
suspenseState: SuspenseState,
3096
const primaryChildFragment: Fiber = (workInProgress.child: any);
3097
primaryChildFragment.memoizedState =
3098
mountSuspenseOffscreenState(renderLanes);
3099
+ primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(
3100
+ current,
3101
+ didPrimaryChildrenDefer,
3102
+ renderLanes,
3103
+ );
3104
workInProgress.memoizedState = SUSPENDED_MARKER;
3105
return fallbackChildFragment;
3106
}