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

Renimated calls findNodeHandle with class instances, which is a slow path in React #6719

Closed
gaearon opened this issue Nov 18, 2024 · 4 comments · Fixed by #6736
Closed

Renimated calls findNodeHandle with class instances, which is a slow path in React #6719

gaearon opened this issue Nov 18, 2024 · 4 comments · Fixed by #6736
Assignees
Labels
Missing repro This issue need minimum repro scenario Platform: Android This issue is specific to Android Platform: iOS This issue is specific to iOS Platform: Web This issue is specific to web

Comments

@gaearon
Copy link
Contributor

gaearon commented Nov 18, 2024

Description

findNodeHandle is a notoriously slow path in React — in fact, the function it's calling internally is literally called findCurrentFiberUsingSlowPath. This is quite inefficient and should be avoided whenever possible.

As @kmagiera suggested, filing an issue about it.

While doing it with native refs is fine (it'll exit early before going into the slow path), calling it on a class instance triggers the bad codepath. I see Reanimated doing this in a few places:

Screenshot 2024-11-18 at 01 33 31 Screenshot 2024-11-18 at 01 28 51 Screenshot 2024-11-18 at 01 29 27

It would be nice to audit all findNodeHandle callsites and remove any that pass class component instances.

Steps to reproduce

See above

Snack or a link to a repository

https://github.com/software-mansion/react-native-reanimated

Reanimated version

3.16.1

React Native version

0.74.1

Platforms

Android, iOS, macOS, Web

JavaScript runtime

Hermes

Workflow

React Native

Architecture

Paper (Old Architecture)

Build type

Debug app & dev bundle

Device

iOS simulator

Device model

No response

Acknowledgements

Yes

@github-actions github-actions bot added Platform: Android This issue is specific to Android Platform: iOS This issue is specific to iOS Platform: Web This issue is specific to web Missing repro This issue need minimum repro scenario labels Nov 18, 2024
Copy link

Hey! 👋

The issue doesn't seem to contain a minimal reproduction.

Could you provide a snack or a link to a GitHub repository under your username that reproduces the problem?

@gaearon
Copy link
Contributor Author

gaearon commented Nov 18, 2024

<Animated.View />

@gaearon
Copy link
Contributor Author

gaearon commented Nov 18, 2024

Partial fix: #6720

@piaskowyk
Copy link
Member

Thank you for highlighting another important issue! I've started to refactor how we use findNodeHandler. Here's the PR: link. I plan to adopt a similar approach to what Expo implemented here: expo/expo#33016.

github-merge-queue bot pushed a commit that referenced this issue Nov 22, 2024
## Summary

Partially addresses
#6719.

This is better because it doesn't enter the traversal codepath inside
React. The `findNodeHandle` calculation inside the `Animated.View`
itself is not so bad because it's short circuited inside for native refs
(at least with `View`). Whereas passing a class instance like here
always triggers the slower path in React. Regardless, it's already
computed so why compute again?

## Test plan

I've added console logs in our app to verify whether
`animatedComponent._componentViewTag ===
findNodeHandle(animatedComponent)` and it always turned out true in the
cases I hit.

Not sure if there any cases where those could be different.

Co-authored-by: Krzysztof Piaskowy <krzysztof.piaskowy@swmansion.com>
github-merge-queue bot pushed a commit that referenced this issue Dec 4, 2024
## Summary

This PR addresses the issue reported at
[https://github.com/software-mansion/react-native-reanimated/issues/6719](https://github.com/software-mansion/react-native-reanimated/issues/6719)
and aims to:

- **Unify the method used to obtain the view tag**, as there are
currently several approaches.
- **Avoid passing a class component to the findNodeHandler**. Instead,
we'll pass a ref to the component, similar to what Expo implemented
here:
[https://github.com/expo/expo/pull/33016](https://github.com/expo/expo/pull/33016).
- **Limit unnecessary invocations of findNodeHandler** to no more than
one call per render.
- **Remove the invocation of findHostInstance from Paper renderer** on
the New Architecture.

**Additional Remarks:**
- When a class component is passed to `createAnimatedComponent`, it will
still fall back to the slow path where we can get a native ref.
- In `NativeEventManager`, we need to call findNodeHandler again after
every render to ensure that the children of `<GestureDetector />`
haven't changed their native tags.
- `LayoutAnimationConfig` still uses findNodeHandler. It requires a
complete refactor of their functionality to eliminate its use, and I
plan to handle this in another PR.
- `findHostInstance_DEPRECATED` always follows the slow path even for
native refs, which is why I've implemented our own version of
`findHostInstance` to optimize the happy path.

Fixes
#6719

Related PRs:
- #6030
- #5960
- #4445
- expo/expo#33016

## Test plan

- [x] check Paper
- [x] check Fabric
- [x] check Web
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Missing repro This issue need minimum repro scenario Platform: Android This issue is specific to Android Platform: iOS This issue is specific to iOS Platform: Web This issue is specific to web
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants