facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
119.18k stars 24.32k forks source link

Long text in inverted Flatlist causes huge performance drop on Android #30034

Closed divonelnc closed 6 months ago

divonelnc commented 4 years ago

Description

I recently upgraded to react 0.63.2 thanks to the latest Expo SDK 39. I immediately noticed that my most important FlatLists took a huge performance hit on Android (iOs seem unaffected).

After investigating, I found out that it happens when using inverted on a FlatList that contains items with a lot of text (see snack).

The same Flatlist, with the same data, is perfectly smooth when not inverted.

I have yet to test it in production, as the latest Expo SDK is causing trouble that stops me from building the app.

React Native version:

react-native: https://github.com/expo/react-native/archive/sdk-39.0.0.tar.gz => 0.63.2

Steps To Reproduce

Provide a detailed list of steps that reproduce the issue.

  1. Create a Flatlist that renders items that contain a lot of text
  2. Set the Flatlist as inverted

Expected Results

The Flatlist should be as smooth when inverted as when normal.

Snack, code example, screenshot, or link to a repository:

https://snack.expo.io/@divone/4c8d68

karthik-balasubramanyam15 commented 1 year ago

+1 I even tried to use Animated Section List instead of chat list and still facing the same issue with inverted.

thanksyouall commented 1 year ago

I have a problem that any inverted list on Android slows down when scrolling. It's not freezing, it's the touch processing. If I try to scroll quickly with my finger, I can't do it. I don't have this problem on a non-flipped list, though. The same problem in ScrollView.

anatooly commented 1 year ago

This add more perfomance when scrolling flatlist on last 0.71.8, android 11, samsung galaxy Unbelievable so many years, android apps lags of inverted FlatList

@MayheMatan try this

index.js (in your app)

import ViewReactNativeStyleAttributes from 'react-native/Libraries/Components/View/ReactNativeStyleAttributes';
ViewReactNativeStyleAttributes.scaleY = true;

Then patch RN 0.71 (react-native+0.71.1.patch)

diff --git a/node_modules/react-native/Libraries/Lists/VirtualizedList.js b/node_modules/react-native/Libraries/Lists/VirtualizedList.js
index 2629142..4e60aad 100644
--- a/node_modules/react-native/Libraries/Lists/VirtualizedList.js
+++ b/node_modules/react-native/Libraries/Lists/VirtualizedList.js
@@ -29,6 +29,7 @@ import {findNodeHandle} from '../ReactNative/RendererProxy';
 import flattenStyle from '../StyleSheet/flattenStyle';
 import StyleSheet from '../StyleSheet/StyleSheet';
 import clamp from '../Utilities/clamp';
+import Platform from '../Utilities/Platform';
 import infoLog from '../Utilities/infoLog';
 import {CellRenderMask} from './CellRenderMask';
 import ChildListCollection from './ChildListCollection';
@@ -1840,9 +1841,7 @@ export default class VirtualizedList extends StateSafePureComponent<
 }

 const styles = StyleSheet.create({
-  verticallyInverted: {
-    transform: [{scaleY: -1}],
-  },
+  verticallyInverted: Platform.OS === 'android' ? { scaleY: -1 } : { transform: [{scaleY: -1}] },
   horizontallyInverted: {
     transform: [{scaleX: -1}],
   },
fukemy commented 1 year ago

still problem in react native 0.71.8, so sad

hannojg commented 1 year ago

Not entirely sure, but I think this PR fixes this issue as well!

claudiozam commented 1 year ago

In React Native 0.72.3 the issue persist. Now the VirtualizedList is in another location @react-native/virtualized-lists/List

anatooly commented 1 year ago

npx patch-package @react-native/virtualized-lists

patches/@react-native+virtualized-lists+0.72.6.patch

diff --git a/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js b/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js
index 8a23e81..ca17f79 100644
--- a/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js
+++ b/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js
@@ -30,6 +30,7 @@ import {
   View,
   StyleSheet,
   findNodeHandle,
+  Platform,
 } from 'react-native';
 import Batchinator from '../Interaction/Batchinator';
 import clamp from '../Utilities/clamp';
@@ -2056,9 +2057,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
 }

 const styles = StyleSheet.create({
-  verticallyInverted: {
-    transform: [{scaleY: -1}],
-  },
+  verticallyInverted: Platform.OS === 'android' ? { scaleY: -1 } : { transform: [{scaleY: -1}] },
   horizontallyInverted: {
     transform: [{scaleX: -1}],
   },
Andrija00 commented 1 year ago

In react native versions 0.71+ to stop performance drop on Android turn off inverted FlatList and add this : style={{transform: [{rotate: '180deg'}]}}, also in add this style in renderItem that is in flat list., also add this if you want to add scroll bar on the right side you can use showsVerticalScrollIndicator={false}. This fixed our chat app where we had lag on many android device when we have 10k char messages.

fukemy commented 1 year ago

@Andrija00 dont do this, instead of styles flatlist and component just styles flatlist 1 time by:

diff --git a/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js b/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js
index 8a23e81..ca17f79 100644
--- a/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js
+++ b/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js
@@ -30,6 +30,7 @@ import {
   View,
   StyleSheet,
   findNodeHandle,
+  Platform,
 } from 'react-native';
 import Batchinator from '../Interaction/Batchinator';
 import clamp from '../Utilities/clamp';
@@ -2056,9 +2057,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
 }

 const styles = StyleSheet.create({
-  verticallyInverted: {
-    transform: [{scaleY: -1}],
-  },
+  verticallyInverted: Platform.OS === 'android' ? { scaleY: -1 } : { transform: [{scaleY: -1}] },
   horizontallyInverted: {
     transform: [{scaleX: -1}],
   },
Andrija00 commented 1 year ago

@Andrija00 dont do this, instead of styles flatlist and component just styles flatlist 1 time by:

diff --git a/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js b/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js
index 8a23e81..ca17f79 100644
--- a/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js
+++ b/node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js
@@ -30,6 +30,7 @@ import {
   View,
   StyleSheet,
   findNodeHandle,
+  Platform,
 } from 'react-native';
 import Batchinator from '../Interaction/Batchinator';
 import clamp from '../Utilities/clamp';
@@ -2056,9 +2057,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
 }

 const styles = StyleSheet.create({
-  verticallyInverted: {
-    transform: [{scaleY: -1}],
-  },
+  verticallyInverted: Platform.OS === 'android' ? { scaleY: -1 } : { transform: [{scaleY: -1}] },
   horizontallyInverted: {
     transform: [{scaleX: -1}],
   },

I can't use transform scaleY because we have performance issue with that. In the past classic scaleY worked fine but transform scaleY is still causing issues on 10k char messages

hannojg commented 1 year ago

A fix for this has landed on main already:

We are working on getting these commits in a next upcoming v0.72+ version. Meanwhile you can try apply the diffs from the commit 😊

Andrija00 commented 1 year ago

I see but I am not using Expo or Virtualized List. I am using basic flatList from React Native and rotate will fix the issue. Thanks for help!

hannojg commented 1 year ago

VirtualizedList is the base component that FlatList uses to implement the list.

anatooly commented 1 year ago

@Andrija00 are you check using shopify/FlashList for you chat (10k char messages)?

fmorau commented 1 year ago

@hannojg do you have an idea when it will go out?

scaleY does not work anymore on 0.72 with new arch (just updated) for "top level view" containers, which I used over all types of messages in my chat - so now I need to refactor to scaleY each and every deeply nested View/Text, which has content directly in it to make it work back again 😬

Andrija00 commented 1 year ago

@anatooly We had issues using FlashList in the past for our ChatScreen component so we stick with FlatList

Nasseratic commented 1 year ago

@hannojg great work!! 💪 😍

hannojg commented 1 year ago

The fix is part of RN 0.72.4, you can upgrade and test 😊

retrixe commented 1 year ago

Perhaps this issue should be closed?

kelset commented 1 year ago

if anyone can confirm that it's fixed I'd be happy to close

retrixe commented 1 year ago

The issue seems fixed for me after updating my app @kelset I don't experience any performance issues anymore on either the new or old architecture, the UI thread's fps is solid now

daidonpah commented 1 year ago

~Unfortunately for me updating did not resolve the issue.~ On Samsung S23 Ultra Android 13, when removing the inverted prop, FlatList behaves perfectly fine as it should, running at smooth 120fps. Adding the inverted prop sporadically brings the fps down to 0.5 and a lot of frame drops. After updating to RN 0.72.4 it seemed liked the issue "improved" at first, but after 20 seconds of scrolling, same performance drop again.

EDIT: I had tried to play around with FlashList instead and forgotten to change it back to FlatList. By using FlatList the issue does indeed seem to be fixed, although now the scroll indicator is on the left. The remedy in this PR (38073) did not work for me. I tried deleting caches and such, but to no avail. I am using expo under windows and I followed this cache invalidation list. RN 0.72.6 and this is my code:

<FlatList
    data={list}
    renderItem={({ item }) => <ListItem item={item} />}
    inverted
/>

So nothing exotic going on. Vertical scroll bar still on the left.

hannojg commented 1 year ago

@daidonpah Are you sure your flatlist doesn't have any custom styles? Because that may cause the wrong position of the scrollbar.

If you don't, are you able to reproduce in a clean new app? If so, I think I'd be good to open a new issue 😊

mirkos93 commented 1 year ago

@daidonpah Have you solved the issue using FlashList?

Edit: I tried using FlashList and the problem seems to be solved.

foloinfo commented 1 year ago

Looks like the performance issue is fixed with v0.72.4 with this line using {transform: [{scale: -1}]} not scaleY. Thank you for the fix @hannojg

I'm using Expo 48 and it uses "react-native": "0.71.14" so I had to patch myself. This will hide the scrollbar for Android, but better than huge performance drop while I wait to update RN.

const styles = StyleSheet.create({
  inverted: {
    ...Platform.select({
      android: {
        transform: [{ scale: -1 }],
      },
    })
  }
})

...

return (
  <FlatList
    // inverted={true} on Android 33+ will cause performance issue
    inverted={Platform.OS === 'ios'}
    // apply the inverted style on android
    style={styles.inverted}
    // hide the scroll indicator on android because it shows on the left
    showsVerticalScrollIndicator={Platform.OS === 'ios'}
    listFooterComponent={
      <View style={styles.inverted}>
        <Header/>
      </View>
    }
    renderItem={({ item }) => {
      return (
        <View style={styles.inverted}>
          {renderItem(item)}
        </View>
      )
    }}
  />
)
retrixe commented 1 year ago

@foloinfo on earlier versions this workaround works without compromising the scrollbar: https://github.com/facebook/react-native/issues/30034#issuecomment-780547496 https://github.com/facebook/react-native/issues/30034#issuecomment-1277360480

github-actions[bot] commented 6 months ago

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

github-actions[bot] commented 6 months ago

This issue was closed because it has been stalled for 7 days with no activity.

JJSLIoT commented 1 month ago

Not stale!

elias96 commented 1 month ago

Keep this open amigo

retrixe commented 1 month ago

This issue has been fixed in recent versions of React Native unless you are still experiencing it, in which case it may be more appropriate to open a new issue

The fix is part of RN 0.72.4, you can upgrade and test 😊