Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[core][iOS] Drop proxiedProperties prop #22280

Merged
merged 6 commits into from
Apr 30, 2023

Conversation

tsapeta
Copy link
Member

@tsapeta tsapeta commented Apr 26, 2023

Why

Expo native component's props are scoped under single proxiedProperties prop. This has many downsides and we would rather get rid of it and pass all props as they are, without scoping.

How

On the old architecture:

  • Added each prop to propTypes in the view config so React Native doesn't error when it validates the props
  • Instead of listening for changes only in proxiedProperties setter, I hooked into the setProps(_:forView:) function in the ComponentData object which is called for each props update

On the new architecture:

  • Instead of reading a single proxiedProperties prop, ExpoViewProps will be iterating over all props and adding them to a C++ map with prop values stored as folly::dynamic
  • When the props update comes in, the map is moved from the old props object (sourceProps) to the new object and then overridden with the updated props (rawProps)
  • The map is then converted to Objective-C values and passed to ExpoFabricView (Swift)

Note that on the JavaScript side, proxiedProperties are still passed to the native view on Android platform. This will be implemented separately.

Also updated the test that depended upon this prop.

Test Plan

  • Native views seem to work fine in bare-expo on iOS
  • All examples in fabric-tester work as expected on iOS
  • All CI checks pass on 391600e commit (the later one skipped CI checks because it only modifies the changelog)

Warning
It probably breaks on Android with Fabric enabled, but we're going to address this in a separate PR.

@expo-bot expo-bot added the bot: suggestions ExpoBot has some suggestions label Apr 26, 2023
@tsapeta tsapeta force-pushed the @tsapeta/ios/remove-proxied-properties branch from a1a2504 to 391600e Compare April 27, 2023 13:34
@expo-bot expo-bot added bot: passed checks ExpoBot has nothing to complain about and removed bot: suggestions ExpoBot has some suggestions labels Apr 27, 2023
@tsapeta tsapeta changed the title [core] Drop proxiedProperties prop [core][iOS] Drop proxiedProperties prop Apr 27, 2023
@tsapeta tsapeta marked this pull request as ready for review April 27, 2023 15:28
Copy link
Contributor

@Kudo Kudo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leaving some nit comments here. mostly looks promising 👏

for eventName in eventNames {
if let viewManager = moduleHolder?.viewManager {
for prop in viewManager.props {
// `id` allows every type to be passed in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is not clear to me what the id is. could you explain more details?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React Native puts some Objective-C types (e.g. NSString, NSNumber, BOOL) as the values in the propTypes of the view config, which are then used to create a method's signature of the prop setter and to know how to convert these props.
See RCTModuleMethod.mm and RCTConvert.m where id: selector just returns itself and leaves the value unconverted.

It's basically the same as here

return ["NSDictionary", "__custom__"]
where we had to describe proxiedProperties as NSDictionary.

proxiedProperties(
facebook::react::convertRawProp(context, rawProps, "proxiedProperties", sourceProps.proxiedProperties, {})) {
}
propsMap(propsMapFromProps(sourceProps, rawProps)) {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
propsMap(propsMapFromProps(sourceProps, rawProps)) {}
propsMap(std::move(propsMapFromProps(sourceProps, rawProps))) {}

not pretty sure whether it's correct. if yes, nice to have a move semantic here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

screenshot_2023-04-29_at_18 52 50

Since this object is already temporary, doing a move would be redundant and slower

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, i was wrong for this, the move is not necessary because it's already temporary object.

*/
std::unordered_map<std::string, folly::dynamic> propsMapFromProps(const ExpoViewProps &sourceProps, const react::RawProps &rawProps) {
// Move the contents of the source props map – the source props instance will not be used anymore.
std::unordered_map<std::string, folly::dynamic> propsMap = std::move(sourceProps.propsMap);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Kudo do you think the move here is safe? As far as I know, the source props will not be used anymore and the propsMap is used only once per the lifetime of the ExpoViewProps instance 🤔 We could do a copy if you're not sure.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

at first glance, it's strange to me because there's const ExpoViewProps &sourceProps in the function declaration and we won't like to mutate the sourceProps. i think it's from react-native to pass sourceProps as a const reference. however, since the propsMaps is controlled by us. that's somehow reasonable. let's keep it as-is.

@tsapeta tsapeta force-pushed the @tsapeta/ios/remove-proxied-properties branch from 3d1a63d to 98154ea Compare April 29, 2023 17:01
@tsapeta tsapeta merged commit b2cd439 into main Apr 30, 2023
@tsapeta tsapeta deleted the @tsapeta/ios/remove-proxied-properties branch April 30, 2023 12:16
lukmccall added a commit that referenced this pull request May 1, 2023
# Why

This a follow-up to the #22280.

# How

So, I manually exported all the properties defined in the view component through the view manager. It's interesting to note that the same code seems to work fine with fabric without any changes made to the `ExpoViewProps` class. I don't know much about fabric components, so there might be something important that I'm missing here. But for now, let's go ahead with merging it. I'll look into it further to figure out why it's working with fabric as well.

# Test Plan

- bare-expo ✅
- fabric-tester ✅
douglowder pushed a commit that referenced this pull request May 2, 2023
# Why

This a follow-up to the #22280.

# How

So, I manually exported all the properties defined in the view component through the view manager. It's interesting to note that the same code seems to work fine with fabric without any changes made to the `ExpoViewProps` class. I don't know much about fabric components, so there might be something important that I'm missing here. But for now, let's go ahead with merging it. I'll look into it further to figure out why it's working with fabric as well.

# Test Plan

- bare-expo ✅
- fabric-tester ✅
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bot: passed checks ExpoBot has nothing to complain about
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants