(current, workInProgress, renderLanes)
| 20277 | } |
| 20278 | |
| 20279 | function updateSuspenseComponent(current, workInProgress, renderLanes) { |
| 20280 | var nextProps = workInProgress.pendingProps; // This is used by DevTools to force a boundary to suspend. |
| 20281 | |
| 20282 | { |
| 20283 | if (shouldSuspend(workInProgress)) { |
| 20284 | workInProgress.flags |= DidCapture; |
| 20285 | } |
| 20286 | } |
| 20287 | |
| 20288 | var suspenseContext = suspenseStackCursor.current; |
| 20289 | var showFallback = false; |
| 20290 | var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags; |
| 20291 | |
| 20292 | if (didSuspend || shouldRemainOnFallback(suspenseContext, current)) { |
| 20293 | // Something in this boundary's subtree already suspended. Switch to |
| 20294 | // rendering the fallback children. |
| 20295 | showFallback = true; |
| 20296 | workInProgress.flags &= ~DidCapture; |
| 20297 | } else { |
| 20298 | // Attempting the main content |
| 20299 | if (current === null || current.memoizedState !== null) { |
| 20300 | // This is a new mount or this boundary is already showing a fallback state. |
| 20301 | // Mark this subtree context as having at least one invisible parent that could |
| 20302 | // handle the fallback state. |
| 20303 | // Avoided boundaries are not considered since they cannot handle preferred fallback states. |
| 20304 | { |
| 20305 | suspenseContext = addSubtreeSuspenseContext(suspenseContext, InvisibleParentSuspenseContext); |
| 20306 | } |
| 20307 | } |
| 20308 | } |
| 20309 | |
| 20310 | suspenseContext = setDefaultShallowSuspenseContext(suspenseContext); |
| 20311 | pushSuspenseContext(workInProgress, suspenseContext); // OK, the next part is confusing. We're about to reconcile the Suspense |
| 20312 | // boundary's children. This involves some custom reconciliation logic. Two |
| 20313 | // main reasons this is so complicated. |
| 20314 | // |
| 20315 | // First, Legacy Mode has different semantics for backwards compatibility. The |
| 20316 | // primary tree will commit in an inconsistent state, so when we do the |
| 20317 | // second pass to render the fallback, we do some exceedingly, uh, clever |
| 20318 | // hacks to make that not totally break. Like transferring effects and |
| 20319 | // deletions from hidden tree. In Concurrent Mode, it's much simpler, |
| 20320 | // because we bailout on the primary tree completely and leave it in its old |
| 20321 | // state, no effects. Same as what we do for Offscreen (except that |
| 20322 | // Offscreen doesn't have the first render pass). |
| 20323 | // |
| 20324 | // Second is hydration. During hydration, the Suspense fiber has a slightly |
| 20325 | // different layout, where the child points to a dehydrated fragment, which |
| 20326 | // contains the DOM rendered by the server. |
| 20327 | // |
| 20328 | // Third, even if you set all that aside, Suspense is like error boundaries in |
| 20329 | // that we first we try to render one tree, and if that fails, we render again |
| 20330 | // and switch to a different tree. Like a try/catch block. So we have to track |
| 20331 | // which branch we're currently rendering. Ideally we would model this using |
| 20332 | // a stack. |
| 20333 | |
| 20334 | if (current === null) { |
| 20335 | // Initial mount |
| 20336 | // Special path for hydration |
no test coverage detected
searching dependent graphs…