-
Notifications
You must be signed in to change notification settings - Fork 24.4k
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
Improve rendering performance for complex UIs (especially on Android) #20254
Comments
Lots of great points - thanks for the thoughtful analysis! We have some longer term projects looking to address a lot of these issues, but you might be able to improve things in the short term as well. Can you describe more specifically the concrete performance issues you're seeing? Is it that initial render is taking too long? Or are you seeing dropped frames while scrolling? Both? Something else? |
@sahrens The biggest problem we are seeing is on initial render. We believe that is due to the native layer creating views for every component as part of initial layout. This also causes memory pressure on particularly large forms that we believe also could be avoided with a virtualized container that acts more like |
@sahrens The flame graph in in the description above is one I captured from an initial render on a Nexus 5X of an especially complex UI. It helped exaggerate the performance issues we were seeing. There are also render time issues with a virtualized list where we'll get chunks of empty scrolling area while waiting for the That being said, once the views actually get added to the screen on Android it is very performant. We typically see it maintaining 60fps with only a short stutter after the Edit: Also render times on a Moto G4 Plus is especially bad due to the low clock rate on a single thread. |
These are known patterns that can be tweaked for different work loads and has been found to work quite well in many scenarios, so I think you'll be able to get it working well for you too. You'll most likely see the most success by optimizing your product code, though - one of the best bang-for-your-buck optimizations is going to be proper use of Once you've done that and you're still seeing issues, the next thing to do is look at the size of your rows and limit your first render to just the content that fits on the screen (or less, if you want) with the As for blank content and memory pressure, there are a couple levers you can pull in I'm glad you're seeing good framerates, though - that's the fundamental advantage of the Let me know if any of this could be clarified in the docs: https://facebook.github.io/react-native/docs/flatlist |
@sahrens Thanks for the feedback. I can assure you that we have done everything you recommend before posting this. We have spent significant time optimizing our React code such that for the majority of the cases, the performance is fine (although better on iOS than Android). We use However, as I said in my initial post, We are very hopeful that some of the work being done as part of Fabric will help in this regard but of course we have very limited visibility into what is being done other than watching the PRs that merge into this repo with interest. |
I'm not sure how UICollectionView or a similar component/API would help you with initial render then - can you expand on that? Is it possible to break down those complex forms into more granular rows? |
I believe the advantage that We have a simplified fully-native implementation on iOS that parses our form JSON into a model that maps components into sections and columns. We then do a layout pass in a custom The That said, I am assuming that the time-consuming part of the React Native initial render is creating all of the views, rather than time spent in Yoga calculating layout for all of them. One of the reasons we love React Native is being able to use flex for our layout, which is admittedly more complicated than our simple native layout logic. But I suspect that using Yoga to build I'm happy to collect more detailed profiling data for initial rendering of our forms on iOS if that would help, similar to what my colleague David did on Android. |
Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as "For Discussion" or "Good first issue" and I will leave it open. Thank you for your contributions. |
Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information. |
For Discussion
We have a React Native app that renders custom forms fetched from a server. These UIs can be arbitrarily complex, with multiple columns containing potentially many (hundreds) of components, including date-time inputs, images, dropdowns, etc.
For a native version of this app, we would use
UICollectionView
on iOS andRecyclerView
on Android. Unfortunately, the currentVirtualizedList
implementations in React Native are not conducive to the types of complex layouts we need to render. And the performance when not using aVirtualizedList
can be quite bad, especially on Android which we have measured as taking at least 2x as long to render as iOS.Possible solutions that we believe would help:
A more powerful virtualized container that knows which components should be rendered on the screen and manages the process of fetching and rendering only the necessary views as the user scrolls. Something akin to an iOS
UICollectionView
which treats layout and rendering as separate tasks and keeps a pool of reusable views. Ideally this new virtualized container would be implemented at the native layer and maybe hook into the existingUICollectionView
andRecyclerView
containers provided by iOS and Android.We believe that even with the current implementation, performance on Android could be improved with a more efficient interface between the Java and native layers. There is quite a bit of overhead when using JNI and there appear to be many more Java-native calls being made than need to be. The following performance profile shows that iteration calls [1] and array size retrievals [2] were both long-running calls. The latter actually fetches the full array to calculate the size, even though the array itself isn't used. In some cases having it fetch the full array makes sense. However the initial size call shouldn’t need to.
The text was updated successfully, but these errors were encountered: