diff --git a/packages/react-native/Libraries/Animated/shouldUseTurboAnimatedModule.js b/packages/react-native/Libraries/Animated/shouldUseTurboAnimatedModule.js index 0a780617e48309..2758cc734699c3 100644 --- a/packages/react-native/Libraries/Animated/shouldUseTurboAnimatedModule.js +++ b/packages/react-native/Libraries/Animated/shouldUseTurboAnimatedModule.js @@ -8,10 +8,15 @@ * @format */ +import * as ReactNativeFeatureFlags from '../../src/private/featureflags/ReactNativeFeatureFlags'; import Platform from '../Utilities/Platform'; function shouldUseTurboAnimatedModule(): boolean { - return Platform.OS === 'ios' && global.RN$Bridgeless === true; + if (ReactNativeFeatureFlags.cxxNativeAnimatedEnabled()) { + return false; + } else { + return Platform.OS === 'ios' && global.RN$Bridgeless === true; + } } export default shouldUseTurboAnimatedModule; diff --git a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h index d9b2c79bb3f87e..ceac3eecb0978e 100644 --- a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h +++ b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h @@ -67,7 +67,7 @@ NS_ASSUME_NONNULL_BEGIN forShadowView:(const facebook::react::ShadowView &)shadowView; - (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag - changedProps:(NSDictionary *)props + changedProps:(folly::dynamic)props componentDescriptor:(const facebook::react::ComponentDescriptor &)componentDescriptor; @end diff --git a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm index 2cd125a5cc145c..e6503ffd622467 100644 --- a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm +++ b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm @@ -282,25 +282,34 @@ - (void)setIsJSResponder:(BOOL)isJSResponder } - (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag - changedProps:(NSDictionary *)props + changedProps:(folly::dynamic)props 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(); + UIView *componentView = [_componentViewRegistry findComponentViewWithTag:reactTag]; + if (!componentView) { + RCTLogWarn(@"Attempted to update view with tag %ld, but it no longer exists", (long)reactTag); + return; + } + SurfaceId surfaceId = RCTSurfaceIdForView(componentView); Props::Shared oldProps = [componentView props]; Props::Shared newProps = componentDescriptor.cloneProps( - PropsParserContext{surfaceId, *_contextContainer.get()}, oldProps, RawProps(convertIdToFollyDynamic(props))); + PropsParserContext{surfaceId, *_contextContainer.get()}, oldProps, RawProps(std::move(props))); NSSet *propKeys = componentView.propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN ?: [NSSet new]; - propKeys = [propKeys setByAddingObjectsFromArray:props.allKeys]; + 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; const auto &newViewProps = static_cast(*newProps); - if (props[@"transform"]) { + if (updatesTransform) { auto layoutMetrics = LayoutMetrics(); layoutMetrics.frame.size.width = componentView.layer.bounds.size.width; layoutMetrics.frame.size.height = componentView.layer.bounds.size.height; @@ -309,7 +318,7 @@ - (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag componentView.layer.transform = newTransform; } } - if (props[@"opacity"] && componentView.layer.opacity != (float)newViewProps.opacity) { + if (updatesOpacity && componentView.layer.opacity != (float)newViewProps.opacity) { componentView.layer.opacity = newViewProps.opacity; } diff --git a/packages/react-native/React/Fabric/RCTScheduler.h b/packages/react-native/React/Fabric/RCTScheduler.h index f5df6a938c98cf..ed585390890b1d 100644 --- a/packages/react-native/React/Fabric/RCTScheduler.h +++ b/packages/react-native/React/Fabric/RCTScheduler.h @@ -42,6 +42,7 @@ NS_ASSUME_NONNULL_BEGIN blockNativeResponder:(BOOL)blockNativeResponder forShadowView:(const facebook::react::ShadowView &)shadowView; +- (void)schedulerDidSynchronouslyUpdateViewOnUIThread:(facebook::react::Tag)reactTag props:(folly::dynamic)props; @end /** diff --git a/packages/react-native/React/Fabric/RCTScheduler.mm b/packages/react-native/React/Fabric/RCTScheduler.mm index 28450b2fc29c22..b8efdebfecc472 100644 --- a/packages/react-native/React/Fabric/RCTScheduler.mm +++ b/packages/react-native/React/Fabric/RCTScheduler.mm @@ -68,8 +68,8 @@ void schedulerDidSendAccessibilityEvent(const ShadowView &shadowView, const std: void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic &props) override { - // Does nothing. - // This delegate method is not currently used on iOS. + RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_; + [scheduler.delegate schedulerDidSynchronouslyUpdateViewOnUIThread:tag props:props]; } private: diff --git a/packages/react-native/React/Fabric/RCTSurfacePresenter.h b/packages/react-native/React/Fabric/RCTSurfacePresenter.h index 7c28b3773624ca..a6796cf1802d47 100644 --- a/packages/react-native/React/Fabric/RCTSurfacePresenter.h +++ b/packages/react-native/React/Fabric/RCTSurfacePresenter.h @@ -65,7 +65,8 @@ NS_ASSUME_NONNULL_BEGIN - (nullable RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag; -- (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props; +- (void)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props; +- (void)schedulerDidSynchronouslyUpdateViewOnUIThread:(ReactTag)tag props:(folly::dynamic)props; - (void)setupAnimationDriverWithSurfaceHandler:(const facebook::react::SurfaceHandler &)surfaceHandler; diff --git a/packages/react-native/React/Fabric/RCTSurfacePresenter.mm b/packages/react-native/React/Fabric/RCTSurfacePresenter.mm index ad1abd5ec2498c..1e675096b3121d 100644 --- a/packages/react-native/React/Fabric/RCTSurfacePresenter.mm +++ b/packages/react-native/React/Fabric/RCTSurfacePresenter.mm @@ -148,28 +148,34 @@ - (UIView *)findComponentViewWithTag_DO_NOT_USE_DEPRECATED:(NSInteger)tag return componentView; } -- (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props +- (void)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props +{ + ReactTag tag = [reactTag integerValue]; + [self schedulerDidSynchronouslyUpdateViewOnUIThread:tag props:convertIdToFollyDynamic(props)]; +} + +- (void)schedulerDidSynchronouslyUpdateViewOnUIThread:(ReactTag)tag props:(folly::dynamic)props { RCTScheduler *scheduler = [self scheduler]; if (!scheduler) { - return NO; + return; } - ReactTag tag = [reactTag integerValue]; UIView *componentView = [_mountingManager.componentViewRegistry findComponentViewWithTag:tag]; if (componentView == nil) { - return NO; // This view probably isn't managed by Fabric + return; // This view probably isn't managed by Fabric } ComponentHandle handle = [[componentView class] componentDescriptorProvider].handle; auto *componentDescriptor = [scheduler findComponentDescriptorByHandle_DO_NOT_USE_THIS_IS_BROKEN:handle]; if (!componentDescriptor) { - return YES; + return; } - [_mountingManager synchronouslyUpdateViewOnUIThread:tag changedProps:props componentDescriptor:*componentDescriptor]; - return YES; + [_mountingManager synchronouslyUpdateViewOnUIThread:tag + changedProps:std::move(props) + componentDescriptor:*componentDescriptor]; } - (void)setupAnimationDriverWithSurfaceHandler:(const facebook::react::SurfaceHandler &)surfaceHandler diff --git a/packages/react-native/React/Modules/RCTSurfacePresenterStub.h b/packages/react-native/React/Modules/RCTSurfacePresenterStub.h index 9cf334854744ca..aea607083a0594 100644 --- a/packages/react-native/React/Modules/RCTSurfacePresenterStub.h +++ b/packages/react-native/React/Modules/RCTSurfacePresenterStub.h @@ -32,7 +32,7 @@ NS_ASSUME_NONNULL_BEGIN - (id)createFabricSurfaceForModuleName:(NSString *)moduleName initialProperties:(NSDictionary *)initialProperties; - (nullable UIView *)findComponentViewWithTag_DO_NOT_USE_DEPRECATED:(NSInteger)tag; -- (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props; +- (void)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props; - (void)addObserver:(id)observer; - (void)removeObserver:(id)observer; diff --git a/packages/react-native/ReactCommon/react/utils/platform/ios/react/utils/FollyConvert.h b/packages/react-native/ReactCommon/react/utils/platform/ios/react/utils/FollyConvert.h index 3ec64dccad104d..0967daba2342da 100644 --- a/packages/react-native/ReactCommon/react/utils/platform/ios/react/utils/FollyConvert.h +++ b/packages/react-native/ReactCommon/react/utils/platform/ios/react/utils/FollyConvert.h @@ -12,6 +12,7 @@ namespace facebook::react { folly::dynamic convertIdToFollyDynamic(id json); -id convertFollyDynamicToId(const folly::dynamic& dyn); +id convertFollyDynamicToId(const folly::dynamic &dyn); +NSArray *extractKeysFromFollyDynamic(const folly::dynamic &dyn); } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/utils/platform/ios/react/utils/FollyConvert.mm b/packages/react-native/ReactCommon/react/utils/platform/ios/react/utils/FollyConvert.mm index c1860e89fe9d8f..fe42ba85b80476 100644 --- a/packages/react-native/ReactCommon/react/utils/platform/ios/react/utils/FollyConvert.mm +++ b/packages/react-native/ReactCommon/react/utils/platform/ios/react/utils/FollyConvert.mm @@ -113,4 +113,20 @@ id convertFollyDynamicToId(const folly::dynamic &dyn) return nil; } +NSArray *extractKeysFromFollyDynamic(const folly::dynamic &dyn) +{ + NSMutableArray *result = [NSMutableArray new]; + + if (dyn.type() == folly::dynamic::OBJECT) { + for (const auto &elem : dyn.items()) { + NSString *key = [[NSString alloc] initWithBytes:elem.first.c_str() + length:elem.first.size() + encoding:NSUTF8StringEncoding]; + [result addObject:key]; + } + } + + return result; +} + } // namespace facebook::react