From 7c100bfed4e833544ef5ca4fec3693c6c6dff177 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Wed, 29 Jan 2020 11:32:21 -0800 Subject: [PATCH] Check if there's a partial tree before restarting If a partial render expires, we should stay in the concurrent path (performConcurrentWorkOnRoot); we'll stop yielding, but the rest of the behavior remains the same. We will only revert to the sync path (performSyncWorkOnRoot) when starting on a new level. This approach prevents partially completed concurrent work from being discarded. --- packages/react-reconciler/src/ReactFiberWorkLoop.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index a4664613ac..ac548ea66b 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -644,9 +644,16 @@ function performConcurrentWorkOnRoot(root, didTimeout) { // event time. The next update will compute a new event time. currentEventTime = NoWork; - if (didTimeout) { - // The render task took too long to complete. Mark the current time as - // expired to synchronously render all expired work in a single batch. + // Check if the render expired. If so, restart at the current time so that we + // can finish all the expired work in a single batch. However, we should only + // do this if we're starting a new tree. If we're in the middle of an existing + // tree, we'll continue working on that (without yielding) so that the work + // doesn't get dropped. If there's another expired level after that, we'll hit + // this path again, at which point we can batch all the subsequent levels + // together. + if (didTimeout && workInProgress === null) { + // Mark the current time as expired to synchronously render all expired work + // in a single batch. const currentTime = requestCurrentTimeForUpdate(); markRootExpiredAtTime(root, currentTime); // This will schedule a synchronous callback.