From 2c8aeb5e550fdff6e06ac94136434305eac0cbfc Mon Sep 17 00:00:00 2001 From: Peter Abbondanzo Date: Mon, 30 Mar 2026 22:08:06 -0700 Subject: [PATCH] Fix Fabric shadow tree not syncing after native-driven animation completes Summary: When `cxxNativeAnimatedEnabled` is true but `useSharedAnimatedBackend` is false, the JS-side `scheduleUpdate()` call in `useAnimatedProps` was being skipped on animation completion. The code assumed the C++ shared animation backend would handle syncing the shadow tree, but that path only runs when `useSharedAnimatedBackend` is also true. This left a gap where neither the JS side nor the C++ side synced the Fabric shadow tree after a `useNativeDriver: true` animation completed. The shadow tree retained stale animation values (e.g. `translateX: 100` from a slide-in animation), causing `measure()` to return incorrect coordinates. On VR, this broke Pressability hit-testing for controller input since the measured responder region didn't match the actual view position. The fix adds `useSharedAnimatedBackend` as an additional condition, so `scheduleUpdate()` only gets skipped when both flags are true (meaning the C++ `AnimationEndSync` path is actually active). Changelog: [Internal] Differential Revision: D98808989 --- .../src/private/animated/createAnimatedPropsHook.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/react-native/src/private/animated/createAnimatedPropsHook.js b/packages/react-native/src/private/animated/createAnimatedPropsHook.js index 0d5745be8fe1..cc06c8682f89 100644 --- a/packages/react-native/src/private/animated/createAnimatedPropsHook.js +++ b/packages/react-native/src/private/animated/createAnimatedPropsHook.js @@ -61,6 +61,8 @@ export default function createAnimatedPropsHook( const [, scheduleUpdate] = useReducer(count => count + 1, 0); const onUpdateRef = useRef(null); const timerRef = useRef(null); + const sharedAnimatedBackendEnabled = + ReactNativeFeatureFlags.useSharedAnimatedBackend(); const rootTag = useContext(RootTagContext); @@ -136,7 +138,8 @@ export default function createAnimatedPropsHook( // Check 2: this is an animation driven by native. // In native driven animations, this callback is only called once the animation completes. const shouldRemoveJsSync = - ReactNativeFeatureFlags.cxxNativeAnimatedEnabled(); + ReactNativeFeatureFlags.cxxNativeAnimatedEnabled() && + sharedAnimatedBackendEnabled; if (isFabricNode && !shouldRemoveJsSync) { // Call `scheduleUpdate` to synchronise Fiber and Shadow tree. // Must not be called in Paper. @@ -212,7 +215,7 @@ export default function createAnimatedPropsHook( } }; }, - [node], + [node, sharedAnimatedBackendEnabled], ); const callbackRef = useRefEffect(refEffect);