Skip to content

Commit e0e1087

Browse files
sammy-SCfacebook-github-bot
authored andcommitted
introduce an option to drive animations with folly::dynamic (facebook#51470)
Summary: changelog: [internal] To support C++ Native Animated and prevent unnecessary conversion between `folly::dynamic` <-> and `NSDictionary`, a method to apply `folly::dynamic` changes needs to be exposed on RCTMountingManager. Previously I tried to change existing method `synchronouslyUpdateViewOnUIThread` to take folly::dynamic instead of `NSDictionary`. However this requires a change where we would expose C++ API to Objective-C class only, breaking build system in open source. This approach was backed out in D74881580. In this diff, I take an alternative approach and expose two methods to apply animation changes: - Keep the existing API `synchronouslyUpdateViewOnUIThread` as is. This way, Objective-C Native Animated does not need to change. - Introduce new method for `[RCTSurfacePresenter schedulerDidSynchronouslyUpdateViewOnUIThread]` which accepts `folly::dynamic`. This is used by C++ Native Animated only Differential Revision: D74885607
1 parent 6399cae commit e0e1087

File tree

6 files changed

+43
-9
lines changed

6 files changed

+43
-9
lines changed

packages/react-native/React/Fabric/Mounting/RCTMountingManager.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ NS_ASSUME_NONNULL_BEGIN
6767
forShadowView:(const facebook::react::ShadowView &)shadowView;
6868

6969
- (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag
70-
changedProps:(NSDictionary *)props
70+
changedProps:(folly::dynamic)props
7171
componentDescriptor:(const facebook::react::ComponentDescriptor &)componentDescriptor;
7272
@end
7373

packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -282,25 +282,34 @@ - (void)setIsJSResponder:(BOOL)isJSResponder
282282
}
283283

284284
- (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag
285-
changedProps:(NSDictionary *)props
285+
changedProps:(folly::dynamic)props
286286
componentDescriptor:(const ComponentDescriptor &)componentDescriptor
287287
{
288288
RCTAssertMainQueue();
289+
NSArray<NSString *> *propsKeysToBeUpdated = extractKeysFromFollyDynamic(props);
290+
bool updatesTransform = props.find("transform") != props.items().end();
291+
bool updatesOpacity = props.find("opacity") != props.items().end();
292+
289293
UIView<RCTComponentViewProtocol> *componentView = [_componentViewRegistry findComponentViewWithTag:reactTag];
294+
if (!componentView) {
295+
RCTLogWarn(@"Attempted to update view with tag %ld, but it no longer exists", (long)reactTag);
296+
return;
297+
}
298+
290299
SurfaceId surfaceId = RCTSurfaceIdForView(componentView);
291300
Props::Shared oldProps = [componentView props];
292301
Props::Shared newProps = componentDescriptor.cloneProps(
293-
PropsParserContext{surfaceId, *_contextContainer.get()}, oldProps, RawProps(convertIdToFollyDynamic(props)));
302+
PropsParserContext{surfaceId, *_contextContainer.get()}, oldProps, RawProps(std::move(props)));
294303

295304
NSSet<NSString *> *propKeys = componentView.propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN ?: [NSSet new];
296-
propKeys = [propKeys setByAddingObjectsFromArray:props.allKeys];
305+
propKeys = [propKeys setByAddingObjectsFromArray:propsKeysToBeUpdated];
297306
componentView.propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN = nil;
298307
[componentView updateProps:newProps oldProps:oldProps];
299308
componentView.propKeysManagedByAnimated_DO_NOT_USE_THIS_IS_BROKEN = propKeys;
300309

301310
const auto &newViewProps = static_cast<const ViewProps &>(*newProps);
302311

303-
if (props[@"transform"]) {
312+
if (updatesTransform) {
304313
auto layoutMetrics = LayoutMetrics();
305314
layoutMetrics.frame.size.width = componentView.layer.bounds.size.width;
306315
layoutMetrics.frame.size.height = componentView.layer.bounds.size.height;
@@ -309,7 +318,7 @@ - (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag
309318
componentView.layer.transform = newTransform;
310319
}
311320
}
312-
if (props[@"opacity"] && componentView.layer.opacity != (float)newViewProps.opacity) {
321+
if (updatesOpacity && componentView.layer.opacity != (float)newViewProps.opacity) {
313322
componentView.layer.opacity = newViewProps.opacity;
314323
}
315324

packages/react-native/React/Fabric/RCTSurfacePresenter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ NS_ASSUME_NONNULL_BEGIN
6666
- (nullable RCTFabricSurface *)surfaceForRootTag:(ReactTag)rootTag;
6767

6868
- (void)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props;
69+
- (void)schedulerDidSynchronouslyUpdateViewOnUIThread:(ReactTag)tag props:(folly::dynamic)props;
6970

7071
- (void)setupAnimationDriverWithSurfaceHandler:(const facebook::react::SurfaceHandler &)surfaceHandler;
7172

packages/react-native/React/Fabric/RCTSurfacePresenter.mm

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,18 @@ - (UIView *)findComponentViewWithTag_DO_NOT_USE_DEPRECATED:(NSInteger)tag
149149
}
150150

151151
- (void)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props
152+
{
153+
ReactTag tag = [reactTag integerValue];
154+
[self schedulerDidSynchronouslyUpdateViewOnUIThread:tag props:convertIdToFollyDynamic(props)];
155+
}
156+
157+
- (void)schedulerDidSynchronouslyUpdateViewOnUIThread:(ReactTag)tag props:(folly::dynamic)props
152158
{
153159
RCTScheduler *scheduler = [self scheduler];
154160
if (!scheduler) {
155161
return;
156162
}
157163

158-
ReactTag tag = [reactTag integerValue];
159164
UIView<RCTComponentViewProtocol> *componentView =
160165
[_mountingManager.componentViewRegistry findComponentViewWithTag:tag];
161166
if (componentView == nil) {
@@ -168,7 +173,9 @@ - (void)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictiona
168173
return;
169174
}
170175

171-
[_mountingManager synchronouslyUpdateViewOnUIThread:tag changedProps:props componentDescriptor:*componentDescriptor];
176+
[_mountingManager synchronouslyUpdateViewOnUIThread:tag
177+
changedProps:std::move(props)
178+
componentDescriptor:*componentDescriptor];
172179
}
173180

174181
- (void)setupAnimationDriverWithSurfaceHandler:(const facebook::react::SurfaceHandler &)surfaceHandler

packages/react-native/ReactCommon/react/utils/platform/ios/react/utils/FollyConvert.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace facebook::react {
1313

1414
folly::dynamic convertIdToFollyDynamic(id json);
15-
id convertFollyDynamicToId(const folly::dynamic& dyn);
15+
id convertFollyDynamicToId(const folly::dynamic &dyn);
16+
NSArray<NSString *> *extractKeysFromFollyDynamic(const folly::dynamic &dyn);
1617

1718
} // namespace facebook::react

packages/react-native/ReactCommon/react/utils/platform/ios/react/utils/FollyConvert.mm

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,20 @@ id convertFollyDynamicToId(const folly::dynamic &dyn)
113113
return nil;
114114
}
115115

116+
NSArray<NSString *> *extractKeysFromFollyDynamic(const folly::dynamic &dyn)
117+
{
118+
NSMutableArray<NSString *> *result = [NSMutableArray new];
119+
120+
if (dyn.type() == folly::dynamic::OBJECT) {
121+
for (const auto &elem : dyn.items()) {
122+
NSString *key = [[NSString alloc] initWithBytes:elem.first.c_str()
123+
length:elem.first.size()
124+
encoding:NSUTF8StringEncoding];
125+
[result addObject:key];
126+
}
127+
}
128+
129+
return result;
130+
}
131+
116132
} // namespace facebook::react

0 commit comments

Comments
 (0)