Implement potential fix for mounting errors during synchronous state updates (v2)

Summary:
Changelog: [internal]

This is a new attempt at fixing mounting errors during synchronous state updates after what we tried in https://github.com/facebook/react-native/pull/44015.

That fix didn't work because `dispatchMountItems` actually makes a copy of the mount items that it's going to process, so when we added the mount items to the list they were actually not being picked up by the current processing.

This changes the fix to call `dispatchMountItems` as many times as needed, while there are mount items to process in the list.

Reviewed By: sammy-SC

Differential Revision: D57107212

fbshipit-source-id: 46988a71daae15d70399258f850653046d0790ff
This commit is contained in:
Rubén Norte
2024-05-08 12:36:06 -07:00
committed by Facebook GitHub Bot
parent 958f8e2bb5
commit fd299509df
@@ -105,40 +105,53 @@ public class MountItemDispatcher {
if (ReactNativeFeatureFlags.forceBatchingMountItemsOnAndroid()) {
mInDispatch = true;
}
final boolean didDispatchItems;
try {
didDispatchItems = dispatchMountItems();
} catch (Throwable e) {
mReDispatchCounter = 0;
throw e;
} finally {
// Clean up after running dispatchMountItems - even if an exception was thrown
mInDispatch = false;
}
// We call didDispatchMountItems regardless of whether we actually dispatched anything, since
// NativeAnimatedModule relies on this for executing any animations that may have been scheduled
mItemDispatchListener.didDispatchMountItems();
// Decide if we want to try reentering
if (mReDispatchCounter < 10 && didDispatchItems) {
// Executing twice in a row is normal. Only log after that point.
if (mReDispatchCounter > 2) {
ReactSoftExceptionLogger.logSoftException(
TAG,
new ReactNoCrashSoftException(
"Re-dispatched "
+ mReDispatchCounter
+ " times. This indicates setState (?) is likely being called too many times"
+ " during mounting."));
try {
boolean didDispatchItems = true;
// Dispatch as many mount items as we find. Some mount items might
// trigger state updates that trigger more mount items. This will
// process them correctly.
while (didDispatchItems) {
didDispatchItems = dispatchMountItems();
}
} finally {
mInDispatch = false;
}
} else {
final boolean didDispatchItems;
try {
didDispatchItems = dispatchMountItems();
} catch (Throwable e) {
mReDispatchCounter = 0;
throw e;
} finally {
// Clean up after running dispatchMountItems - even if an exception was thrown
mInDispatch = false;
}
mReDispatchCounter++;
tryDispatchMountItems();
// We call didDispatchMountItems regardless of whether we actually dispatched anything, since
// NativeAnimatedModule relies on this for executing any animations that may have been
// scheduled
mItemDispatchListener.didDispatchMountItems();
// Decide if we want to try reentering
if (mReDispatchCounter < 10 && didDispatchItems) {
// Executing twice in a row is normal. Only log after that point.
if (mReDispatchCounter > 2) {
ReactSoftExceptionLogger.logSoftException(
TAG,
new ReactNoCrashSoftException(
"Re-dispatched "
+ mReDispatchCounter
+ " times. This indicates setState (?) is likely being called too many times"
+ " during mounting."));
}
mReDispatchCounter++;
tryDispatchMountItems();
}
mReDispatchCounter = 0;
}
mReDispatchCounter = 0;
}
@UiThread