@@ -1897,6 +1897,15 @@ function commitRootImpl(root, renderPriorityLevel) {
1897
1897
remainingLanes = root . pendingLanes ;
1898
1898
1899
1899
// 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.
1900
1909
if ( remainingLanes === NoLanes ) {
1901
1910
// If there's no remaining work, we can clear the set of already failed
1902
1911
// error boundaries.
@@ -1909,23 +1918,6 @@ function commitRootImpl(root, renderPriorityLevel) {
1909
1918
}
1910
1919
}
1911
1920
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
-
1929
1921
onCommitRootDevTools ( finishedWork . stateNode , renderPriorityLevel ) ;
1930
1922
1931
1923
if ( enableUpdaterTracking ) {
@@ -1964,6 +1956,25 @@ function commitRootImpl(root, renderPriorityLevel) {
1964
1956
flushPassiveEffects ( ) ;
1965
1957
}
1966
1958
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
+
1967
1978
// If layout work was scheduled, flush it now.
1968
1979
flushSyncCallbacks ( ) ;
1969
1980
0 commit comments