@@ -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