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

Change typeof for prototype check to only process plain objects as mappers inputs #4258

Merged
merged 2 commits into from
Mar 24, 2023

Conversation

kmagiera
Copy link
Member

@kmagiera kmagiera commented Mar 22, 2023

Summary

This PR changes the logic on when we scan nested objects provided as mappers' inputs. Before this change we'd do a typeof check to test whether it is an object. This check however passes on derived objects such as HostObjects, Maps, etc. Since these types of objects can have very complex structures we want to avoid scanning them recursively and only do that for plain object. We achieve this by testing its prototype and comparing with Object.prototype.

We encountered this error when passing complex objects as style properties to mappers. Specifically with react-native-skia integration on AnimateTextOnPath example where Path object is used as mappers' input. We only found it problematic on Web however, because on Native Path object is implemented as HostObject which in turn does not support Object.values (we always get empty array for JSI's HostObjects on native). On web, however, the browser would get stuck on recursively processing this complex object which was taking very long on Firefox and was crashing the app on Chrome.

Test plan

Run test examples in the app
Tested this on web with react-native-skia reanimated AnimateTextOnPath example where a HostObject is used inside a mapper and it was taking ages to process that object recursively.

@wcandillon
Copy link
Contributor

whoop whoop 🙌🏼

@@ -115,7 +115,10 @@ export function createMapperRegistry() {
}
} else if (inputs.addListener) {
resultArray.push(inputs);
} else if (typeof inputs === 'object') {
} else if (inputs.__proto__ === Object.prototype) {
Copy link
Member

Choose a reason for hiding this comment

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

The __proto__ property seems to be deprecated, maybe could we use Object.getPrototypeOf?

Copy link
Member Author

Choose a reason for hiding this comment

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

sure, that's a good suggestion

@@ -115,7 +115,10 @@ export function createMapperRegistry() {
}
} else if (inputs.addListener) {
resultArray.push(inputs);
} else if (typeof inputs === 'object') {
} else if (Object.getPrototypeOf(inputs) === Object.prototype) {
Copy link
Contributor

Choose a reason for hiding this comment

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

not sure if that's valid scenario but if inputs is null or undefined it will throw an error

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think it can be null, otherwise typescript would've alerted us

Copy link
Member Author

Choose a reason for hiding this comment

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

if it was null, than the previous else if that I'm not chaging would already crash the app as it is accessing a addListener property of inputs

@kmagiera kmagiera added this pull request to the merge queue Mar 24, 2023
Merged via the queue into main with commit 66db7cf Mar 24, 2023
@kmagiera kmagiera deleted the fix-mappers-on-web branch March 24, 2023 13:04
@wcandillon
Copy link
Contributor

is there a way to track in which version of Reanimated this will be shipped?

@tomekzaw
Copy link
Member

@wcandillon it's already released in 3.1.0

@wcandillon
Copy link
Contributor

I can confirm that the fix works perfectly thank you ❤️

fluiddot pushed a commit to wordpress-mobile/react-native-reanimated that referenced this pull request Jun 5, 2023
…ppers inputs (software-mansion#4258)

## Summary

This PR changes the logic on when we scan nested objects provided as
mappers' inputs. Before this change we'd do a `typeof` check to test
whether it is an object. This check however passes on derived objects
such as HostObjects, Maps, etc. Since these types of objects can have
very complex structures we want to avoid scanning them recursively and
only do that for plain object. We achieve this by testing its prototype
and comparing with Object.prototype.

We encountered this error when passing complex objects as style
properties to mappers. Specifically with react-native-skia integration
on
[AnimateTextOnPath](https://github.com/Shopify/react-native-skia/blob/main/example/src/Examples/Reanimated/AnimateTextOnPath.tsx)
example where Path object is used as mappers' input. We only found it
problematic on Web however, because on Native Path object is implemented
as HostObject which in turn does not support Object.values (we always
get empty array for JSI's HostObjects on native). On web, however, the
browser would get stuck on recursively processing this complex object
which was taking very long on Firefox and was crashing the app on
Chrome.

## Test plan

Run test examples in the app
Tested this on web with react-native-skia reanimated AnimateTextOnPath
example where a HostObject is used inside a mapper and it was taking
ages to process that object recursively.
@wcandillon
Copy link
Contributor

Gang, is it possible that this fix has been only shipped for Reanimated 3?
We are trying to push Reanimated as the only tool to do animation and we have an integration with Reanimated 2 as well now (working on the JS thread). But this bug appears again with Reanimated 2 is it possible that this should be shipped in v2 as well?

@tomekzaw
Copy link
Member

tomekzaw commented Oct 2, 2023

@wcandillon Yes, this PR fixes only v3. Also it cannot be simply backported to v2 because in Reanimated v2 mappers were implemented in C++ but in v3 they have been moved to JS code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants