From e43419c7ee248770bb58e4fd2b387554f60c7b9b Mon Sep 17 00:00:00 2001 From: Zeya Peng Date: Tue, 21 Jul 2026 07:35:59 -0700 Subject: [PATCH] Guard forced-native animations from JS updates (#57617) Summary: Prevent animation nodes from entering the JS update path when native driving is forced. If the invariant is violated, emit a one-time warning and stop before JS-driven reconciliation. Changelog: [Internal] Reviewed By: rubennorte Differential Revision: D112822632 --- .../private/animated/createAnimatedPropsHook.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/react-native/src/private/animated/createAnimatedPropsHook.js b/packages/react-native/src/private/animated/createAnimatedPropsHook.js index 0d5745be8fe1..0e930cdae4a0 100644 --- a/packages/react-native/src/private/animated/createAnimatedPropsHook.js +++ b/packages/react-native/src/private/animated/createAnimatedPropsHook.js @@ -17,6 +17,7 @@ import AnimatedValue from '../../../Libraries/Animated/nodes/AnimatedValue'; import {isPublicInstance as isFabricPublicInstance} from '../../../Libraries/ReactNative/ReactFabricPublicInstance/ReactFabricPublicInstanceUtils'; import {RootTagContext} from '../../../Libraries/ReactNative/RootTag'; import useRefEffect from '../../../Libraries/Utilities/useRefEffect'; +import warnOnce from '../../../Libraries/Utilities/warnOnce'; import * as ReactNativeFeatureFlags from '../featureflags/ReactNativeFeatureFlags'; import {createAnimatedPropsMemoHook} from './createAnimatedPropsMemoHook'; import NativeAnimatedHelper from './NativeAnimatedHelper'; @@ -52,9 +53,6 @@ export default function createAnimatedPropsHook( ): AnimatedPropsHook { const useAnimatedPropsMemo = createAnimatedPropsMemoHook(allowlist); - const useNativePropsInFabric = - ReactNativeFeatureFlags.shouldUseSetNativePropsInFabric(); - return function useAnimatedProps( props: TProps, ): [ReducedProps, CallbackRef] { @@ -145,6 +143,17 @@ export default function createAnimatedPropsHook( return; } + // TODO: T274006331 - Remove js-only animation once shared backend is fully rolled out + const isNativeDriverForced = + NativeAnimatedHelper.isNativeDriverForced(); + if (isNativeDriverForced) { + warnOnce( + 'animated-force-native-driver-js-update', + 'Animated: Expected the animation node to use the native driver when the native driver is forced.', + ); + return; + } + if ( typeof instance !== 'object' || typeof instance?.setNativeProps !== 'function' @@ -160,6 +169,8 @@ export default function createAnimatedPropsHook( return instance.setNativeProps(node.__getAnimatedValue()); } + const useNativePropsInFabric = + ReactNativeFeatureFlags.shouldUseSetNativePropsInFabric(); if (!useNativePropsInFabric) { // Check 5: setNativeProps are disabled. return scheduleUpdate();