Skip to content

Commit

Permalink
Improve setting props of the Interop Layer (#41942)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #41942

Previously, every time a component was updated, we were passing all the props to the interoperated component.
With this change, we are going to only pass the props that are changed.

As a safety feature, if the new codepath is not able to detect the type of the prop properly, it will fall back to the previous behavior.

## Changelog:
[Internal] - Only pass props to the interoperated component when they changes

Reviewed By: sammy-SC

Differential Revision: D51755764

fbshipit-source-id: 0185d2cceeab2a1e45b87d5a1e82ab06e00aa82d
  • Loading branch information
cipolleschi authored and facebook-github-bot committed Dec 14, 2023
1 parent 201d2d1 commit b098297
Showing 1 changed file with 87 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ @implementation RCTLegacyViewManagerInteropCoordinator {
*/
NSMutableArray<id<RCTBridgeMethod>> *_moduleMethods;
NSMutableDictionary<NSString *, id<RCTBridgeMethod>> *_moduleMethodsByName;

NSDictionary<NSString *, id> *_oldProps;
}

- (instancetype)initWithComponentData:(RCTComponentData *)componentData
Expand Down Expand Up @@ -100,11 +102,13 @@ - (void)setProps:(const folly::dynamic &)props forView:(UIView *)view
{
if (props.isObject()) {
NSDictionary<NSString *, id> *convertedProps = convertFollyDynamicToId(props);
[_componentData setProps:convertedProps forView:view];
NSDictionary<NSString *, id> *diffedProps = [self _diffProps:convertedProps];
[_componentData setProps:diffedProps forView:view];

if ([view respondsToSelector:@selector(didSetProps:)]) {
[view performSelector:@selector(didSetProps:) withObject:[convertedProps allKeys]];
[view performSelector:@selector(didSetProps:) withObject:[diffedProps allKeys]];
}
_oldProps = convertedProps;
}
}

Expand Down Expand Up @@ -248,4 +252,85 @@ - (void)_lookupModuleMethodsIfNecessary
}
}

- (NSDictionary<NSString *, id> *)_diffProps:(NSDictionary<NSString *, id> *)newProps
{
NSMutableDictionary<NSString *, id> *diffedProps = [NSMutableDictionary new];

[newProps enumerateKeysAndObjectsUsingBlock:^(NSString *key, id newProp, __unused BOOL *stop) {
id oldProp = _oldProps[key];
if ([self _prop:newProp isDifferentFrom:oldProp]) {
diffedProps[key] = newProp;
}
}];

return diffedProps;
}

- (BOOL)_prop:(id)oldProp isDifferentFrom:(id)newProp
{
// Check for JSON types.
// JSON types can be of:
// * number
// * bool
// * String
// * Array
// * Objects => Dictionaries in ObjectiveC
// * Null

// Check for NULL
BOOL bothNil = !oldProp && !newProp;
if (bothNil) {
return NO;
}

BOOL onlyOneNil = (oldProp && !newProp) || (!oldProp && newProp);
if (onlyOneNil) {
return YES;
}

if ([self _propIsSameNumber:oldProp second:newProp]) {
// Boolean should be captured by NSNumber
return NO;
}

if ([self _propIsSameString:oldProp second:newProp]) {
return NO;
}

if ([self _propIsSameArray:oldProp second:newProp]) {
return NO;
}

if ([self _propIsSameObject:oldProp second:newProp]) {
return NO;
}

// Previous behavior, fallback to YES
return YES;
}

- (BOOL)_propIsSameNumber:(id)first second:(id)second
{
return [first isKindOfClass:[NSNumber class]] && [second isKindOfClass:[NSNumber class]] &&
[(NSNumber *)first isEqualToNumber:(NSNumber *)second];
}

- (BOOL)_propIsSameString:(id)first second:(id)second
{
return [first isKindOfClass:[NSString class]] && [second isKindOfClass:[NSString class]] &&
[(NSString *)first isEqualToString:(NSString *)second];
}

- (BOOL)_propIsSameArray:(id)first second:(id)second
{
return [first isKindOfClass:[NSArray class]] && [second isKindOfClass:[NSArray class]] &&
[(NSArray *)first isEqualToArray:(NSArray *)second];
}

- (BOOL)_propIsSameObject:(id)first second:(id)second
{
return [first isKindOfClass:[NSDictionary class]] && [second isKindOfClass:[NSDictionary class]] &&
[(NSDictionary *)first isEqualToDictionary:(NSDictionary *)second];
}

@end

0 comments on commit b098297

Please sign in to comment.