diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 6c548efcb7b..c43306344ca 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -298,6 +298,11 @@ const definitions: FeatureFlagDefinitions = { defaultValue: false, description: 'Enables Animated to skip non-allowlisted props and styles.', }, + enableAnimatedClearImmediateFix: { + defaultValue: true, + description: + 'Enables an experimental to use the proper clearIntermediate instead of calling the wrong clearTimeout and canceling another timer.', + }, enableAnimatedPropsMemo: { defaultValue: false, description: diff --git a/packages/react-native/src/private/animated/NativeAnimatedHelper.js b/packages/react-native/src/private/animated/NativeAnimatedHelper.js index fac57567b1e..0210d47c6bb 100644 --- a/packages/react-native/src/private/animated/NativeAnimatedHelper.js +++ b/packages/react-native/src/private/animated/NativeAnimatedHelper.js @@ -46,7 +46,7 @@ const isSingleOpBatching = Platform.OS === 'android' && NativeAnimatedModule?.queueAndExecuteBatchedOperations != null && ReactNativeFeatureFlags.animatedShouldUseSingleOp(); -let flushQueueTimeout = null; +let flushQueueImmediate = null; const eventListenerGetValueCallbacks: { [number]: (value: number) => void, @@ -142,9 +142,13 @@ const API = { queueOperations = true; if ( ReactNativeFeatureFlags.animatedShouldDebounceQueueFlush() && - flushQueueTimeout + flushQueueImmediate ) { - clearTimeout(flushQueueTimeout); + if (ReactNativeFeatureFlags.enableAnimatedClearImmediateFix()) { + clearImmediate(flushQueueImmediate); + } else { + clearTimeout(flushQueueImmediate); + } } }, @@ -161,9 +165,9 @@ const API = { invariant(NativeAnimatedModule, 'Native animated module is not available'); if (ReactNativeFeatureFlags.animatedShouldDebounceQueueFlush()) { - const prevTimeout = flushQueueTimeout; - clearImmediate(prevTimeout); - flushQueueTimeout = setImmediate(API.flushQueue); + const prevImmediate = flushQueueImmediate; + clearImmediate(prevImmediate); + flushQueueImmediate = setImmediate(API.flushQueue); } else { API.flushQueue(); } @@ -176,7 +180,7 @@ const API = { NativeAnimatedModule || process.env.NODE_ENV === 'test', 'Native animated module is not available', ); - flushQueueTimeout = null; + flushQueueImmediate = null; if (singleOpQueue.length === 0) { return; @@ -198,7 +202,7 @@ const API = { NativeAnimatedModule || process.env.NODE_ENV === 'test', 'Native animated module is not available', ); - flushQueueTimeout = null; + flushQueueImmediate = null; if (queue.length === 0) { return; diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 8a1fa0354a3..19e42104b5b 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> * @flow strict */ @@ -32,6 +32,7 @@ export type ReactNativeFeatureFlagsJsOnly = { animatedShouldUseSingleOp: Getter, enableAccessToHostTreeInFabric: Getter, enableAnimatedAllowlist: Getter, + enableAnimatedClearImmediateFix: Getter, enableAnimatedPropsMemo: Getter, enableOptimisedVirtualizedCells: Getter, isLayoutAnimationEnabled: Getter, @@ -124,6 +125,11 @@ export const enableAccessToHostTreeInFabric: Getter = createJavaScriptF */ export const enableAnimatedAllowlist: Getter = createJavaScriptFlagGetter('enableAnimatedAllowlist', false); +/** + * Enables an experimental to use the proper clearIntermediate instead of calling the wrong clearTimeout and canceling another timer. + */ +export const enableAnimatedClearImmediateFix: Getter = createJavaScriptFlagGetter('enableAnimatedClearImmediateFix', true); + /** * Enables Animated to analyze props to minimize invalidating `AnimatedProps`. */