(current, workInProgress, renderExpirationTime)
| 21308 | } |
| 21309 | |
| 21310 | function updateSuspenseComponent(current, workInProgress, renderExpirationTime) { |
| 21311 | var mode = workInProgress.mode; |
| 21312 | var nextProps = workInProgress.pendingProps; // This is used by DevTools to force a boundary to suspend. |
| 21313 | |
| 21314 | { |
| 21315 | if (shouldSuspend(workInProgress)) { |
| 21316 | workInProgress.effectTag |= DidCapture; |
| 21317 | } |
| 21318 | } |
| 21319 | |
| 21320 | var suspenseContext = suspenseStackCursor.current; |
| 21321 | var nextDidTimeout = false; |
| 21322 | var didSuspend = (workInProgress.effectTag & DidCapture) !== NoEffect; |
| 21323 | |
| 21324 | if (didSuspend || shouldRemainOnFallback(suspenseContext, current)) { |
| 21325 | // Something in this boundary's subtree already suspended. Switch to |
| 21326 | // rendering the fallback children. |
| 21327 | nextDidTimeout = true; |
| 21328 | workInProgress.effectTag &= ~DidCapture; |
| 21329 | } else { |
| 21330 | // Attempting the main content |
| 21331 | if (current === null || current.memoizedState !== null) { |
| 21332 | // This is a new mount or this boundary is already showing a fallback state. |
| 21333 | // Mark this subtree context as having at least one invisible parent that could |
| 21334 | // handle the fallback state. |
| 21335 | // Boundaries without fallbacks or should be avoided are not considered since |
| 21336 | // they cannot handle preferred fallback states. |
| 21337 | if (nextProps.fallback !== undefined && nextProps.unstable_avoidThisFallback !== true) { |
| 21338 | suspenseContext = addSubtreeSuspenseContext(suspenseContext, InvisibleParentSuspenseContext); |
| 21339 | } |
| 21340 | } |
| 21341 | } |
| 21342 | |
| 21343 | suspenseContext = setDefaultShallowSuspenseContext(suspenseContext); |
| 21344 | pushSuspenseContext(workInProgress, suspenseContext); // This next part is a bit confusing. If the children timeout, we switch to |
| 21345 | // showing the fallback children in place of the "primary" children. |
| 21346 | // However, we don't want to delete the primary children because then their |
| 21347 | // state will be lost (both the React state and the host state, e.g. |
| 21348 | // uncontrolled form inputs). Instead we keep them mounted and hide them. |
| 21349 | // Both the fallback children AND the primary children are rendered at the |
| 21350 | // same time. Once the primary children are un-suspended, we can delete |
| 21351 | // the fallback children — don't need to preserve their state. |
| 21352 | // |
| 21353 | // The two sets of children are siblings in the host environment, but |
| 21354 | // semantically, for purposes of reconciliation, they are two separate sets. |
| 21355 | // So we store them using two fragment fibers. |
| 21356 | // |
| 21357 | // However, we want to avoid allocating extra fibers for every placeholder. |
| 21358 | // They're only necessary when the children time out, because that's the |
| 21359 | // only time when both sets are mounted. |
| 21360 | // |
| 21361 | // So, the extra fragment fibers are only used if the children time out. |
| 21362 | // Otherwise, we render the primary children directly. This requires some |
| 21363 | // custom reconciliation logic to preserve the state of the primary |
| 21364 | // children. It's essentially a very basic form of re-parenting. |
| 21365 | |
| 21366 | if (current === null) { |
| 21367 | // If we're currently hydrating, try to hydrate this boundary. |
no test coverage detected