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

Inverted SectionList/Flatlist/Flashlist has frame drop #35983

Closed
devoren opened this issue Jan 26, 2023 · 16 comments
Closed

Inverted SectionList/Flatlist/Flashlist has frame drop #35983

devoren opened this issue Jan 26, 2023 · 16 comments

Comments

@devoren
Copy link

devoren commented Jan 26, 2023

Description

I want to use a flatlist or flashlist to show a inverted list. But if I use inverted prop on android it works very slow.
Default Flatlist: drops 5-10 FPS in dev mode (UI 60FPS)
Inverted Flatlist: drops 30-40 FPS in dev mode (UI also 20-40FPS)
Default:
default.webm

Inverted:
inverted.webm

Version

0.71.1

Output of npx react-native info

System:
OS: Windows 10 10.0.19044
CPU: (8) x64 Intel(R) Core(TM) i5-10300H CPU @ 2.50GHz
Memory: 3.17 GB / 15.84 GB
Binaries:
Node: 18.12.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.19 - ~\AppData\Roaming\npm\yarn.CMD
npm: 9.2.0 - C:\Program Files\nodejs\npm.CMD
Watchman: Not Found
SDKs:
Android SDK: Not Found
Windows SDK: Not Found
IDEs:
Android Studio: AI-221.6008.13.2211.9477386
Visual Studio: 16.11.31624.102 (Visual Studio Enterprise�2019)
Languages:
Java: 11.0.13 - /c/Program Files/Common Files/Oracle/Java/javapath/javac
npmPackages:
@react-native-community/cli: Not Found
react: 18.2.0 => 18.2.0
react-native: 0.71.1 => 0.71.1
react-native-windows: Not Found
npmGlobalPackages:
react-native: Not Found

Steps to reproduce

  1. Init new RN app
  2. Add Flat list
  3. Set inverted prop to true

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

 const renderItem: ListRenderItem<IMessage> = ({ item, index }) => {
	return (
		<MessageItem id={item.id} message={item.message} date={item.date} />
	)};

 const keyExtractor = ({ id, date }: IMessage) => `${id}_${date}`;

 return (
	<SafeAreaView style={styles.container}>
		<FlatList
			ref={list}
			data={messages}
			keyExtractor={keyExtractor}
			renderItem={renderItem}
			scrollEventThrottle={16}
			contentContainerStyle={{
				paddingVertical: SCALE.XS,
			}}
			showsVerticalScrollIndicator={false}
		/>
	</SafeAreaView>
  );
@cl3i550n
Copy link

@devoren Hi!

Sorry for the English... let's go!

Use the "initialNumToRender" property to render only the first items in the list, while the other items are rendered as the user scrolls. This can help reduce the number of initially rendered elements and therefore improve performance.
Use the "windowSize" property to increase the number of items rendered in each window. This can help reduce the number of elements rendered as the user scrolls, which can also improve performance.
Checks that your data source is updating correctly, preventing unnecessary updates
Checks if the keyExtractor is being used correctly, avoiding unnecessary update
If you're still having performance issues, you might consider using a third-party lib like react-native-largelist to improve performance.

@devoren
Copy link
Author

devoren commented Jan 26, 2023

@cl3i550n Thanks for the quick response! I used these props to improve performance, but it didn't help much. As you said about 3rd party libraries, I'm trying to use flashlist but it also has lags but their documentation says to measure in release mod but don't think there will be big changes. So I tried scaleY: -1 instead of inverted prop but no change. I'm going to try react-native-large-list, if it helps I'll let you know

@decisionnguyen
Copy link

It's worked

diff --git a/node_modules/react-native/Libraries/Lists/VirtualizedList.js b/node_modules/react-native/Libraries/Lists/VirtualizedList.js
index 6de43b7..4baf72c 100644
--- a/node_modules/react-native/Libraries/Lists/VirtualizedList.js
+++ b/node_modules/react-native/Libraries/Lists/VirtualizedList.js
@@ -26,6 +26,8 @@ import {
   computeWindowedRenderLimits,
 } from './VirtualizeUtils';
 
+const Platform = require('../Utilities/Platform');
+
 import * as React from 'react';
 import type {ScrollResponderType} from '../Components/ScrollView/ScrollView';
 import type {ViewStyleProp} from '../StyleSheet/StyleSheet';
@@ -2108,9 +2110,10 @@ function describeNestedLists(childList: {
 }
 
 const styles = StyleSheet.create({
-  verticallyInverted: {
-    transform: [{scaleY: -1}],
-  },
+  verticallyInverted:
+      Platform.OS === 'android'
+          ? {scaleY: -1}
+          : {transform:  [{scaleY: -1}],},
   horizontallyInverted: {
     transform: [{scaleX: -1}],
   },

@devoren
Copy link
Author

devoren commented Jan 27, 2023

@decisionnguyen I don't know why, but it doesn't work for me, if I add this condition, then the inverted prop doesn't work at all :(

@devoren
Copy link
Author

devoren commented Jan 27, 2023

@cl3i550n It doesn't matter which list I use, the UI drops at 30fps, maybe the problem is with react native and not the list?

@cl3i550n
Copy link

@cl3i550n It doesn't matter which list I use, the UI drops at 30fps, maybe the problem is with react native and not the list?

try other device... or change react native version, try disabling hermes... I can't reproduce the problem, for me it works normal without frame drop. Try using your cell phone as an emulator, for a real simulation of the app...

@devoren
Copy link
Author

devoren commented Jan 27, 2023

@cl3i550n What version of RN are you using?

@cl3i550n
Copy link

@cl3i550n What version of RN are you using?

0.71.1

@devoren
Copy link
Author

devoren commented Jan 27, 2023

@cl3i550n I use a flash list on native stack screen, maybe because of that?

@cl3i550n
Copy link

const renderItem: ListRenderItem = ({ item, index }) => {
return (

)};

const keyExtractor = ({ id, date }: IMessage) => ${id}_${date};

return (

<FlatList
ref={list}
data={messages}
keyExtractor={keyExtractor}
renderItem={renderItem}
scrollEventThrottle={16}
contentContainerStyle={{
paddingVertical: SCALE.XS,
}}
showsVerticalScrollIndicator={false}
/>

);

Use the FlatList's initialNumToRender attribute. This attribute specifies the number of items to be rendered at first, which can help improve performance when loading large datasets.

Use the FlatList's windowSize attribute. This attribute specifies the number of items to keep in memory for each side of the screen. This can help reduce the amount of items that need to be rendered and recreated when the user scrolls down the list.

Use the FlatList's removeClippedSubviews attribute. This attribute allows you to disable rendering of items that are off-screen, which can help improve performance when scrolling through the list.

Use the FlatList's onEndReachedThreshold attribute. This attribute specifies the scroll distance in pixels before the end of the list when the onEndReached event fires. This can help prevent extra items from being triggered unnecessarily.

Use the FlatList's maxToRenderPerBatch attribute. This attribute specifies the maximum number of items that will be rendered in a single batch. This can help reduce the number of items that need to be rendered at the same time.

Use the FlatList's updateCellsBatchingPeriod attribute. This attribute specifies the amount of time, in milliseconds, that cell updates will be wrapped before being sent to the rendering process. This can help reduce the number of cell updates that need to be sent at the same time.

Use the FlatList's extraData attribute. This attribute is used to force the FlatList to re-render all items when the data changes.

Use the react-native-performance-monitor library to monitor your application's performance and identify performance bottlenecks.

Here's an example of how you can reverse the order of items in your FlatList without using the inverted property:

const renderItem: ListRenderItem<IMessage> = ({ item, index }) => {
  return (
    <MessageItem id={item.id} message={item.message} date={item.date} />
  )
};

const keyExtractor = ({ id, date }: IMessage) => `${id}_${date}`;

return (
  <SafeAreaView style={styles.container}>
    <FlatList
      ref={list}
      data={messages.slice().reverse()}
      keyExtractor={keyExtractor}
      renderItem={renderItem}
      scrollEventThrottle={16}
      contentContainerStyle={{
        paddingVertical: SCALE.XS,
      }}
      showsVerticalScrollIndicator={false}
    />
  </SafeAreaView>
);

Instead of using the inverted property, we are using the slice() and reverse() method to create an inverted copy of the data array and pass it to the FlatList. This should resolve the performance issue as the list component no longer needs to reverse the order of items on rendering.

Sorry bad english!

@devoren
Copy link
Author

devoren commented Jan 27, 2023

@cl3i550n Thanks for the advice!!! I need inverted prop to invert scroll position, I will try all suggestions

@IshmamR
Copy link

IshmamR commented Feb 4, 2023

After a lot of reading and experimenting, style={{transform: [{rotate: '180deg'}]}} seems to be the best workaround for the time being.

@devoren
Copy link
Author

devoren commented Feb 4, 2023

@IshmamR Thank you, i will try

@glundgrenm
Copy link

glundgrenm commented Feb 16, 2023

After a lot of reading and experimenting, style={{transform: [{rotate: '180deg'}]}} seems to be the best workaround for the time being.

Worked! But the scrollbar went to the left.

@brsaylor2
Copy link

possible duplicate of #35350

@kelset
Copy link
Contributor

kelset commented May 9, 2023

Closing as duplicate of #35350 and #30034 - I'm trying to reduce the number of different issues people are reporting this performance problem with Inverted Flatlist (and especially on Android 13). Please add comments to those issues instead.

@kelset kelset closed this as completed May 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants