Cancel pending commit before starting on root

Moves the cancelTimeout call to right before creating a new work-in-
progress root. Fixes a class of bugs where a pending commit is not
cancelled, causing an incomplete tree to accidentally commit.

In the interest of fixing downstream bugs quickly, I'm landing this
without a test case; I'll add one in a follow up.
This commit is contained in:
Andrew Clark
2019-04-15 16:00:18 -07:00
parent 9ebe1768a8
commit 4221565e15
2 changed files with 9 additions and 17 deletions
+9 -9
View File
@@ -479,15 +479,6 @@ function scheduleCallbackForRoot(
}
}
const timeoutHandle = root.timeoutHandle;
if (timeoutHandle !== noTimeout) {
// The root previous suspended and scheduled a timeout to commit a fallback
// state. Now that we have additional work, cancel the timeout.
root.timeoutHandle = noTimeout;
// $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above
cancelTimeout(timeoutHandle);
}
// Add the current set of interactions to the pending set associated with
// this root.
schedulePendingInteraction(root, expirationTime);
@@ -673,6 +664,15 @@ export function flushControlled(fn: () => mixed): void {
function prepareFreshStack(root, expirationTime) {
root.pendingCommitExpirationTime = NoWork;
const timeoutHandle = root.timeoutHandle;
if (timeoutHandle !== noTimeout) {
// The root previous suspended and scheduled a timeout to commit a fallback
// state. Now that we have additional work, cancel the timeout.
root.timeoutHandle = noTimeout;
// $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above
cancelTimeout(timeoutHandle);
}
if (workInProgress !== null) {
let interruptedWork = workInProgress.return;
while (interruptedWork !== null) {
@@ -1724,11 +1724,3 @@ describe('ReactSuspenseWithNoopRenderer', () => {
expect(ReactNoop.getChildren()).toEqual([span('Loading...')]);
});
});
// TODO:
// An update suspends, timeout is scheduled. Update again with different timeout.
// An update suspends, a higher priority update also suspends, each has different timeouts.
// Can update siblings of a timed out placeholder without suspending
// Pinging during the render phase
// Synchronous thenable
// Start time is computed using earliest suspended time