( root: FiberRoot, lanes: Lanes, shouldYieldForPrerendering: boolean, )
| 2530 | // and more similar. Not sure it makes sense to maintain forked paths. Consider |
| 2531 | // unifying them again. |
| 2532 | function renderRootSync( |
| 2533 | root: FiberRoot, |
| 2534 | lanes: Lanes, |
| 2535 | shouldYieldForPrerendering: boolean, |
| 2536 | ): RootExitStatus { |
| 2537 | const prevExecutionContext = executionContext; |
| 2538 | executionContext |= RenderContext; |
| 2539 | const prevDispatcher = pushDispatcher(root.containerInfo); |
| 2540 | const prevAsyncDispatcher = pushAsyncDispatcher(); |
| 2541 | |
| 2542 | // If the root or lanes have changed, throw out the existing stack |
| 2543 | // and prepare a fresh one. Otherwise we'll continue where we left off. |
| 2544 | if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) { |
| 2545 | if (enableUpdaterTracking) { |
| 2546 | if (isDevToolsPresent) { |
| 2547 | const memoizedUpdaters = root.memoizedUpdaters; |
| 2548 | if (memoizedUpdaters.size > 0) { |
| 2549 | restorePendingUpdaters(root, workInProgressRootRenderLanes); |
| 2550 | memoizedUpdaters.clear(); |
| 2551 | } |
| 2552 | |
| 2553 | // At this point, move Fibers that scheduled the upcoming work from the Map to the Set. |
| 2554 | // If we bailout on this work, we'll move them back (like above). |
| 2555 | // It's important to move them now in case the work spawns more work at the same priority with different updaters. |
| 2556 | // That way we can keep the current update and future updates separate. |
| 2557 | movePendingFibersToMemoized(root, lanes); |
| 2558 | } |
| 2559 | } |
| 2560 | |
| 2561 | workInProgressTransitions = getTransitionsForLanes(root, lanes); |
| 2562 | prepareFreshStack(root, lanes); |
| 2563 | } |
| 2564 | |
| 2565 | if (enableSchedulingProfiler) { |
| 2566 | markRenderStarted(lanes); |
| 2567 | } |
| 2568 | |
| 2569 | let didSuspendInShell = false; |
| 2570 | let exitStatus = workInProgressRootExitStatus; |
| 2571 | outer: do { |
| 2572 | try { |
| 2573 | if ( |
| 2574 | workInProgressSuspendedReason !== NotSuspended && |
| 2575 | workInProgress !== null |
| 2576 | ) { |
| 2577 | // The work loop is suspended. During a synchronous render, we don't |
| 2578 | // yield to the main thread. Immediately unwind the stack. This will |
| 2579 | // trigger either a fallback or an error boundary. |
| 2580 | // TODO: For discrete and "default" updates (anything that's not |
| 2581 | // flushSync), we want to wait for the microtasks the flush before |
| 2582 | // unwinding. Will probably implement this using renderRootConcurrent, |
| 2583 | // or merge renderRootSync and renderRootConcurrent into the same |
| 2584 | // function and fork the behavior some other way. |
| 2585 | const unitOfWork = workInProgress; |
| 2586 | const thrownValue = workInProgressThrownValue; |
| 2587 | switch (workInProgressSuspendedReason) { |
| 2588 | case SuspendedOnHydration: { |
| 2589 | // Selective hydration. An update flowed into a dehydrated tree. |
no test coverage detected