Skip to content

Commit

Permalink
Make the interop-layer work with components with custom name (#41207)
Browse files Browse the repository at this point in the history
Summary:
This should fix
#37905 (comment)

When working on react-native-fast-image, we realized that the interop layer does not work for components where the exported name is different from the iOS class.

To fix this, we can use the Bridge to retrieve the actual view manager, given the component name.

This solution should be much more robust than making assumptions on the ViewManager name, given the ComponentName.

On top of that, we realized tha the interop layer was not calling `didSetProps` after setting the props, so we are invoking that.

bypass-github-export-checks

[iOS][Fixed] - Add support for Components with custom names in the interop layer.

Pull Request resolved: #41207

Test Plan: Tested locally on an app created in 0.72 and 0.73 in Bridge and Bridgeless mode.

Reviewed By: cortinico

Differential Revision: D50698172

Pulled By: cipolleschi

fbshipit-source-id: 49aee905418515b0204febbbe6a67c0114f37029
  • Loading branch information
cipolleschi authored and fortmarek committed Nov 8, 2023
1 parent 5858fd7 commit e40af84
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,45 @@ static Class getViewManagerFromComponentName(const std::string &componentName)
return nil;
}

static std::shared_ptr<void> const constructCoordinator(
ContextContainer::Shared const &contextContainer,
ComponentDescriptor::Flavor const &flavor)
static Class getViewManagerClass(const std::string &componentName, RCTBridge *bridge, RCTBridgeProxy *bridgeProxy)
{
Class viewManager = getViewManagerFromComponentName(componentName);
if (viewManager != nil) {
return viewManager;
}

// If all the heuristics fail, let's try to retrieve the view manager from the bridge/bridgeProxy
if (bridge != nil) {
return [[bridge moduleForName:RCTNSStringFromString(componentName)] class];
}

if (bridgeProxy != nil) {
return [[bridgeProxy moduleForName:RCTNSStringFromString(componentName) lazilyLoadIfNecessary:YES] class];
}

return nil;
}

static const std::shared_ptr<void> constructCoordinator(
const ContextContainer::Shared &contextContainer,
const ComponentDescriptor::Flavor &flavor)
{
auto componentName = *std::static_pointer_cast<std::string const>(flavor);
Class viewManagerClass = getViewManagerFromComponentName(componentName);
assert(viewManagerClass);
auto optionalBridge = contextContainer->find<std::shared_ptr<void>>("Bridge");
RCTBridge *bridge;
if (optionalBridge) {
bridge = unwrapManagedObjectWeakly(optionalBridge.value());
}

RCTBridgeProxy *bridgeProxy;
auto optionalBridgeProxy = contextContainer->find<std::shared_ptr<void>>("RCTBridgeProxy");
if (optionalBridgeProxy) {
bridgeProxy = unwrapManagedObjectWeakly(optionalBridgeProxy.value());
}

auto componentName = *std::static_pointer_cast<std::string const>(flavor);
Class viewManagerClass = getViewManagerClass(componentName, bridge, bridgeProxy);
assert(viewManagerClass);

auto optionalEventDispatcher = contextContainer->find<std::shared_ptr<void>>("RCTEventDispatcher");
RCTEventDispatcher *eventDispatcher;
if (optionalEventDispatcher) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ - (void)setProps:(folly::dynamic const &)props forView:(UIView *)view
if (props.isObject()) {
NSDictionary<NSString *, id> *convertedProps = convertFollyDynamicToId(props);
[_componentData setProps:convertedProps forView:view];

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

Expand Down

0 comments on commit e40af84

Please sign in to comment.