From e758e67d53d21d1a9ab610bb4b553e9c3c60cfe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ma=C5=82ecki?= Date: Wed, 28 Jan 2026 06:52:11 -0800 Subject: [PATCH] Fix blocking animating non-layout props through `commitUpdates` after the `View` was synchronously animated (#55340) Summary: This diff fixes edge-case with animating non-layout props through `commitUpdates` path. The non-layout props are animated through the synchronous short-path, skipping yoga layout calculations. In `RCTMountingManager` the `propKeysManagerByAnimated` were set on updated props which are then checked for and blocked in the RCTViewComponentView's `updateProps` method (non-layout props might be applied through the layout path as we animate props in batch that may consists of both types of props). ## Changelog: [iOS][Fixed] - Fixed edge-case with animating non-layout props through the `commitUpdates` path. Reviewed By: zeyap Differential Revision: D91677971 --- .../React/Fabric/Mounting/RCTMountingManager.mm | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm index fa65e055d05d95..68662f06d59bd4 100644 --- a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm +++ b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm @@ -14,6 +14,7 @@ #import #import #import +#import #import #import #import @@ -286,7 +287,6 @@ - (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag componentDescriptor:(const ComponentDescriptor &)componentDescriptor { RCTAssertMainQueue(); - NSArray *propsKeysToBeUpdated = extractKeysFromFollyDynamic(props); bool updatesTransform = props.find("transform") != props.items().end(); bool updatesOpacity = props.find("opacity") != props.items().end(); @@ -296,13 +296,18 @@ - (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag return; } + NSSet *propKeys = componentView.propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN ?: [NSSet new]; + + if (!ReactNativeFeatureFlags::useSharedAnimatedBackend()) { + NSArray *propsKeysToBeUpdated = extractKeysFromFollyDynamic(props); + propKeys = [propKeys setByAddingObjectsFromArray:propsKeysToBeUpdated]; + } + SurfaceId surfaceId = RCTSurfaceIdForView(componentView); Props::Shared oldProps = [componentView props]; Props::Shared newProps = componentDescriptor.cloneProps( PropsParserContext{surfaceId, *_contextContainer}, oldProps, RawProps(std::move(props))); - NSSet *propKeys = componentView.propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN ?: [NSSet new]; - propKeys = [propKeys setByAddingObjectsFromArray:propsKeysToBeUpdated]; componentView.propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN = nil; [componentView updateProps:newProps oldProps:oldProps]; componentView.propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN = propKeys;