Skip to content

Commit 43f8cc4

Browse files
committed
Use callback priority to determine cancellation
1 parent bf6990a commit 43f8cc4

File tree

3 files changed

+46
-15
lines changed

3 files changed

+46
-15
lines changed

packages/react-reconciler/src/ReactFiberWorkLoop.new.js

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -716,29 +716,43 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
716716
// Special case: There's nothing to work on.
717717
if (existingCallbackNode !== null) {
718718
cancelCallback(existingCallbackNode);
719-
root.callbackNode = null;
720-
root.callbackPriority = NoLanePriority;
721719
}
720+
root.callbackNode = null;
721+
root.callbackPriority = NoLanePriority;
722722
return;
723723
}
724724

725725
// Check if there's an existing task. We may be able to reuse it.
726-
if (existingCallbackNode !== null) {
727-
const existingCallbackPriority = root.callbackPriority;
726+
const existingCallbackPriority = root.callbackPriority;
727+
if (
728+
existingCallbackPriority !== NoLanePriority &&
729+
existingCallbackPriority !== InputDiscreteLanePriority
730+
) {
728731
if (existingCallbackPriority === newCallbackPriority) {
729732
// The priority hasn't changed. We can reuse the existing task. Exit.
730733
return;
731734
}
732-
// The priority changed. Cancel the existing callback. We'll schedule a new
733-
// one below.
734-
cancelCallback(existingCallbackNode);
735+
736+
if (existingCallbackNode != null) {
737+
// The priority changed. Cancel the existing callback.
738+
// We'll schedule a new one below.
739+
cancelCallback(existingCallbackNode);
740+
} else {
741+
// TODO: Temporary. This shouldn't happen, but remove after confirmed.
742+
// Using console['error'] to evade Babel and ESLint
743+
console['error'](
744+
'Expected scheduled callback to exist. This error is likely caused by a bug in React. Please file an issue.',
745+
);
746+
}
735747
}
736748

737749
// Schedule a new callback.
738750
let newCallbackNode;
739751
if (newCallbackPriority === SyncLanePriority) {
740752
// Special case: Sync React callbacks are scheduled on a special
741753
// internal queue
754+
755+
// TODO: After enableDiscreteEventMicroTasks lands, we can remove the fake node.
742756
newCallbackNode = scheduleSyncCallback(
743757
performSyncWorkOnRoot.bind(null, root),
744758
);
@@ -1879,6 +1893,7 @@ function commitRootImpl(root, renderPriorityLevel) {
18791893
// commitRoot never returns a continuation; it always finishes synchronously.
18801894
// So we can clear these now to allow a new callback to be scheduled.
18811895
root.callbackNode = null;
1896+
root.callbackPriority = NoLanePriority;
18821897

18831898
// Update the first and last pending times on this root. The new first
18841899
// pending time is whatever is left on the root fiber.

packages/react-reconciler/src/ReactFiberWorkLoop.old.js

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -698,29 +698,43 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
698698
// Special case: There's nothing to work on.
699699
if (existingCallbackNode !== null) {
700700
cancelCallback(existingCallbackNode);
701-
root.callbackNode = null;
702-
root.callbackPriority = NoLanePriority;
703701
}
702+
root.callbackNode = null;
703+
root.callbackPriority = NoLanePriority;
704704
return;
705705
}
706706

707707
// Check if there's an existing task. We may be able to reuse it.
708-
if (existingCallbackNode !== null) {
709-
const existingCallbackPriority = root.callbackPriority;
708+
const existingCallbackPriority = root.callbackPriority;
709+
if (
710+
existingCallbackPriority !== NoLanePriority &&
711+
existingCallbackPriority !== InputDiscreteLanePriority
712+
) {
710713
if (existingCallbackPriority === newCallbackPriority) {
711714
// The priority hasn't changed. We can reuse the existing task. Exit.
712715
return;
713716
}
714-
// The priority changed. Cancel the existing callback. We'll schedule a new
715-
// one below.
716-
cancelCallback(existingCallbackNode);
717+
718+
if (existingCallbackNode != null) {
719+
// The priority changed. Cancel the existing callback.
720+
// We'll schedule a new one below.
721+
cancelCallback(existingCallbackNode);
722+
} else {
723+
// TODO: Temporary. This shouldn't happen, but remove after confirmed.
724+
// Using console['error'] to evade Babel and ESLint
725+
console['error'](
726+
'Expected scheduled callback to exist. This error is likely caused by a bug in React. Please file an issue.',
727+
);
728+
}
717729
}
718730

719731
// Schedule a new callback.
720732
let newCallbackNode;
721733
if (newCallbackPriority === SyncLanePriority) {
722734
// Special case: Sync React callbacks are scheduled on a special
723735
// internal queue
736+
737+
// TODO: After enableDiscreteEventMicroTasks lands, we can remove the fake node.
724738
newCallbackNode = scheduleSyncCallback(
725739
performSyncWorkOnRoot.bind(null, root),
726740
);
@@ -1859,6 +1873,7 @@ function commitRootImpl(root, renderPriorityLevel) {
18591873
// commitRoot never returns a continuation; it always finishes synchronously.
18601874
// So we can clear these now to allow a new callback to be scheduled.
18611875
root.callbackNode = null;
1876+
root.callbackPriority = NoLanePriority;
18621877

18631878
// Update the first and last pending times on this root. The new first
18641879
// pending time is whatever is left on the root fiber.

scripts/error-codes/codes.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,5 +372,6 @@
372372
"381": "This feature is not supported by ReactSuspenseTestUtils.",
373373
"382": "This query has received more parameters than the last time the same query was used. Always pass the exact number of parameters that the query needs.",
374374
"383": "This query has received fewer parameters than the last time the same query was used. Always pass the exact number of parameters that the query needs.",
375-
"384": "Refreshing the cache is not supported in Server Components."
375+
"384": "Refreshing the cache is not supported in Server Components.",
376+
"385": "Expected scheduled callback to exist. This error is likely caused by a bug in React. Please file an issue."
376377
}

0 commit comments

Comments
 (0)