From da1bf8d1d1b83b8cee76e94987d94d9ffba6db51 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Fri, 28 Mar 2025 08:13:39 -0700 Subject: [PATCH] RN: Ship `scheduleAnimatedCleanupInMicrotask` (#50341) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/50341 Ships tge `scheduleAnimatedCleanupInMicrotask` feature flag, which changes the cleanup of `AnimatedProps` to occur in a microtask instead of synchronously during effect cleanup (for unmount) or subsequent mounts (for updates). Changelog: [General][Changed] - When an `Animated` component is unmounted, any completion callbacks will now be called in a microtask instead of during the commit phase. Reviewed By: javache Differential Revision: D71942778 fbshipit-source-id: cbe636d5cff84dfeca2f21ead374609c536e91ad --- .../featureflags/ReactNativeFeatureFlags.config.js | 7 +++---- .../private/animated/__tests__/AnimatedNative-test.js | 9 ++++++--- .../src/private/featureflags/ReactNativeFeatureFlags.js | 6 +++--- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 83b2395ec2d..9dcced14a71 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -582,13 +582,12 @@ const definitions: FeatureFlagDefinitions = { ossReleaseStage: 'none', }, scheduleAnimatedCleanupInMicrotask: { - defaultValue: false, + defaultValue: true, metadata: { - dateAdded: '2025-01-22', description: - 'Changes the cleanup of`AnimatedProps` to occur in a microtask instead of synchronously during effect cleanup (for unmount) or subsequent mounts (for updates).', + 'Changes the cleanup of `AnimatedProps` to occur in a microtask instead of synchronously during effect cleanup (for unmount) or subsequent mounts (for updates).', expectedReleaseValue: true, - purpose: 'experimentation', + purpose: 'release', }, ossReleaseStage: 'none', }, diff --git a/packages/react-native/src/private/animated/__tests__/AnimatedNative-test.js b/packages/react-native/src/private/animated/__tests__/AnimatedNative-test.js index e3a569a2842..442c4a8fca5 100644 --- a/packages/react-native/src/private/animated/__tests__/AnimatedNative-test.js +++ b/packages/react-native/src/private/animated/__tests__/AnimatedNative-test.js @@ -151,7 +151,7 @@ describe('Native Animated', () => { const tag = opacity.__getNativeTag(); await unmount(root); - + jest.runAllTicks(); expect(NativeAnimatedModule.getValue).toBeCalledWith( tag, expect.any(Function), @@ -175,7 +175,7 @@ describe('Native Animated', () => { const tag = opacity.__getNativeTag(); await unmount(root); - + jest.runAllTicks(); expect(NativeAnimatedModule.getValue).toBeCalledWith( tag, expect.any(Function), @@ -404,7 +404,7 @@ describe('Native Animated', () => { expect(NativeAnimatedModule.dropAnimatedNode).not.toHaveBeenCalled(); await unmount(root); - + jest.runAllTicks(); expect( NativeAnimatedModule.disconnectAnimatedNodes, ).toHaveBeenCalledTimes(2); @@ -1387,11 +1387,13 @@ describe('Native Animated', () => { expect(NativeAnimatedModule.restoreDefaultValues).not.toHaveBeenCalled(); await update(root, ); + jest.runAllTicks(); expect(NativeAnimatedModule.restoreDefaultValues).toHaveBeenCalledTimes( 1, ); await unmount(root); + jest.runAllTicks(); // Make sure it doesn't get called on unmount. expect(NativeAnimatedModule.restoreDefaultValues).toHaveBeenCalledTimes( 1, @@ -1416,6 +1418,7 @@ describe('Native Animated', () => { ); await unmount(root); + jest.runAllTicks(); expect( NativeAnimatedModule.disconnectAnimatedNodeFromView, ).toBeCalledWith(propsTag, 1); diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 8e103657bf4..e3434ce42b3 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 */ @@ -137,9 +137,9 @@ export const fixVirtualizeListCollapseWindowSize: Getter = createJavaSc export const isLayoutAnimationEnabled: Getter = createJavaScriptFlagGetter('isLayoutAnimationEnabled', true); /** - * Changes the cleanup of`AnimatedProps` to occur in a microtask instead of synchronously during effect cleanup (for unmount) or subsequent mounts (for updates). + * Changes the cleanup of `AnimatedProps` to occur in a microtask instead of synchronously during effect cleanup (for unmount) or subsequent mounts (for updates). */ -export const scheduleAnimatedCleanupInMicrotask: Getter = createJavaScriptFlagGetter('scheduleAnimatedCleanupInMicrotask', false); +export const scheduleAnimatedCleanupInMicrotask: Getter = createJavaScriptFlagGetter('scheduleAnimatedCleanupInMicrotask', true); /** * Enables use of AnimatedObject for animating transform values.