Skip to content

Commit 720b041

Browse files
committed
Fix failing test added in previous commit
The way we detect a "nested update" is if there's synchronous work remaining at the end of the commit phase. Currently this check happens before we synchronously flush the passive effects. I moved it to after the effects are fired, so that it detects whether synchronous work was scheduled in that phase.
1 parent 082f49f commit 720b041

File tree

2 files changed

+56
-34
lines changed

2 files changed

+56
-34
lines changed

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

+28-17
Original file line numberDiff line numberDiff line change
@@ -1897,6 +1897,15 @@ function commitRootImpl(root, renderPriorityLevel) {
18971897
remainingLanes = root.pendingLanes;
18981898

18991899
// Check if there's remaining work on this root
1900+
// TODO: This is part of the `componentDidCatch` implementation. Its purpose
1901+
// is to detect whether something might have called setState inside
1902+
// `componentDidCatch`. The mechanism is known to be flawed because `setState`
1903+
// inside `componentDidCatch` is itself flawed — that's why we recommend
1904+
// `getDerivedStateFromError` instead. However, it could be improved by
1905+
// checking if remainingLanes includes Sync work, instead of whether there's
1906+
// any work remaining at all (which would also include stuff like Suspense
1907+
// retries or transitions). It's been like this for a while, though, so fixing
1908+
// it probably isn't that urgent.
19001909
if (remainingLanes === NoLanes) {
19011910
// If there's no remaining work, we can clear the set of already failed
19021911
// error boundaries.
@@ -1909,23 +1918,6 @@ function commitRootImpl(root, renderPriorityLevel) {
19091918
}
19101919
}
19111920

1912-
if (includesSomeLane(remainingLanes, (SyncLane: Lane))) {
1913-
if (enableProfilerTimer && enableProfilerNestedUpdatePhase) {
1914-
markNestedUpdateScheduled();
1915-
}
1916-
1917-
// Count the number of times the root synchronously re-renders without
1918-
// finishing. If there are too many, it indicates an infinite update loop.
1919-
if (root === rootWithNestedUpdates) {
1920-
nestedUpdateCount++;
1921-
} else {
1922-
nestedUpdateCount = 0;
1923-
rootWithNestedUpdates = root;
1924-
}
1925-
} else {
1926-
nestedUpdateCount = 0;
1927-
}
1928-
19291921
onCommitRootDevTools(finishedWork.stateNode, renderPriorityLevel);
19301922

19311923
if (enableUpdaterTracking) {
@@ -1964,6 +1956,25 @@ function commitRootImpl(root, renderPriorityLevel) {
19641956
flushPassiveEffects();
19651957
}
19661958

1959+
// Read this again, since a passive effect might have updated it
1960+
remainingLanes = root.pendingLanes;
1961+
if (includesSomeLane(remainingLanes, (SyncLane: Lane))) {
1962+
if (enableProfilerTimer && enableProfilerNestedUpdatePhase) {
1963+
markNestedUpdateScheduled();
1964+
}
1965+
1966+
// Count the number of times the root synchronously re-renders without
1967+
// finishing. If there are too many, it indicates an infinite update loop.
1968+
if (root === rootWithNestedUpdates) {
1969+
nestedUpdateCount++;
1970+
} else {
1971+
nestedUpdateCount = 0;
1972+
rootWithNestedUpdates = root;
1973+
}
1974+
} else {
1975+
nestedUpdateCount = 0;
1976+
}
1977+
19671978
// If layout work was scheduled, flush it now.
19681979
flushSyncCallbacks();
19691980

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

+28-17
Original file line numberDiff line numberDiff line change
@@ -1897,6 +1897,15 @@ function commitRootImpl(root, renderPriorityLevel) {
18971897
remainingLanes = root.pendingLanes;
18981898

18991899
// Check if there's remaining work on this root
1900+
// TODO: This is part of the `componentDidCatch` implementation. Its purpose
1901+
// is to detect whether something might have called setState inside
1902+
// `componentDidCatch`. The mechanism is known to be flawed because `setState`
1903+
// inside `componentDidCatch` is itself flawed — that's why we recommend
1904+
// `getDerivedStateFromError` instead. However, it could be improved by
1905+
// checking if remainingLanes includes Sync work, instead of whether there's
1906+
// any work remaining at all (which would also include stuff like Suspense
1907+
// retries or transitions). It's been like this for a while, though, so fixing
1908+
// it probably isn't that urgent.
19001909
if (remainingLanes === NoLanes) {
19011910
// If there's no remaining work, we can clear the set of already failed
19021911
// error boundaries.
@@ -1909,23 +1918,6 @@ function commitRootImpl(root, renderPriorityLevel) {
19091918
}
19101919
}
19111920

1912-
if (includesSomeLane(remainingLanes, (SyncLane: Lane))) {
1913-
if (enableProfilerTimer && enableProfilerNestedUpdatePhase) {
1914-
markNestedUpdateScheduled();
1915-
}
1916-
1917-
// Count the number of times the root synchronously re-renders without
1918-
// finishing. If there are too many, it indicates an infinite update loop.
1919-
if (root === rootWithNestedUpdates) {
1920-
nestedUpdateCount++;
1921-
} else {
1922-
nestedUpdateCount = 0;
1923-
rootWithNestedUpdates = root;
1924-
}
1925-
} else {
1926-
nestedUpdateCount = 0;
1927-
}
1928-
19291921
onCommitRootDevTools(finishedWork.stateNode, renderPriorityLevel);
19301922

19311923
if (enableUpdaterTracking) {
@@ -1964,6 +1956,25 @@ function commitRootImpl(root, renderPriorityLevel) {
19641956
flushPassiveEffects();
19651957
}
19661958

1959+
// Read this again, since a passive effect might have updated it
1960+
remainingLanes = root.pendingLanes;
1961+
if (includesSomeLane(remainingLanes, (SyncLane: Lane))) {
1962+
if (enableProfilerTimer && enableProfilerNestedUpdatePhase) {
1963+
markNestedUpdateScheduled();
1964+
}
1965+
1966+
// Count the number of times the root synchronously re-renders without
1967+
// finishing. If there are too many, it indicates an infinite update loop.
1968+
if (root === rootWithNestedUpdates) {
1969+
nestedUpdateCount++;
1970+
} else {
1971+
nestedUpdateCount = 0;
1972+
rootWithNestedUpdates = root;
1973+
}
1974+
} else {
1975+
nestedUpdateCount = 0;
1976+
}
1977+
19671978
// If layout work was scheduled, flush it now.
19681979
flushSyncCallbacks();
19691980

0 commit comments

Comments
 (0)