(current, workInProgress, renderLanes)
| 20316 | } |
| 20317 | |
| 20318 | function updateSuspenseComponent(current, workInProgress, renderLanes) { |
| 20319 | var nextProps = workInProgress.pendingProps; // This is used by DevTools to force a boundary to suspend. |
| 20320 | |
| 20321 | { |
| 20322 | if (shouldSuspend(workInProgress)) { |
| 20323 | workInProgress.flags |= DidCapture; |
| 20324 | } |
| 20325 | } |
| 20326 | |
| 20327 | var suspenseContext = suspenseStackCursor.current; |
| 20328 | var showFallback = false; |
| 20329 | var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags; |
| 20330 | |
| 20331 | if (didSuspend || shouldRemainOnFallback(suspenseContext, current)) { |
| 20332 | // Something in this boundary's subtree already suspended. Switch to |
| 20333 | // rendering the fallback children. |
| 20334 | showFallback = true; |
| 20335 | workInProgress.flags &= ~DidCapture; |
| 20336 | } else { |
| 20337 | // Attempting the main content |
| 20338 | if (current === null || current.memoizedState !== null) { |
| 20339 | // This is a new mount or this boundary is already showing a fallback state. |
| 20340 | // Mark this subtree context as having at least one invisible parent that could |
| 20341 | // handle the fallback state. |
| 20342 | // Avoided boundaries are not considered since they cannot handle preferred fallback states. |
| 20343 | { |
| 20344 | suspenseContext = addSubtreeSuspenseContext(suspenseContext, InvisibleParentSuspenseContext); |
| 20345 | } |
| 20346 | } |
| 20347 | } |
| 20348 | |
| 20349 | suspenseContext = setDefaultShallowSuspenseContext(suspenseContext); |
| 20350 | pushSuspenseContext(workInProgress, suspenseContext); // OK, the next part is confusing. We're about to reconcile the Suspense |
| 20351 | // boundary's children. This involves some custom reconciliation logic. Two |
| 20352 | // main reasons this is so complicated. |
| 20353 | // |
| 20354 | // First, Legacy Mode has different semantics for backwards compatibility. The |
| 20355 | // primary tree will commit in an inconsistent state, so when we do the |
| 20356 | // second pass to render the fallback, we do some exceedingly, uh, clever |
| 20357 | // hacks to make that not totally break. Like transferring effects and |
| 20358 | // deletions from hidden tree. In Concurrent Mode, it's much simpler, |
| 20359 | // because we bailout on the primary tree completely and leave it in its old |
| 20360 | // state, no effects. Same as what we do for Offscreen (except that |
| 20361 | // Offscreen doesn't have the first render pass). |
| 20362 | // |
| 20363 | // Second is hydration. During hydration, the Suspense fiber has a slightly |
| 20364 | // different layout, where the child points to a dehydrated fragment, which |
| 20365 | // contains the DOM rendered by the server. |
| 20366 | // |
| 20367 | // Third, even if you set all that aside, Suspense is like error boundaries in |
| 20368 | // that we first we try to render one tree, and if that fails, we render again |
| 20369 | // and switch to a different tree. Like a try/catch block. So we have to track |
| 20370 | // which branch we're currently rendering. Ideally we would model this using |
| 20371 | // a stack. |
| 20372 | |
| 20373 | if (current === null) { |
| 20374 | // Initial mount |
| 20375 | // Special path for hydration |
no test coverage detected
searching dependent graphs…