Skip to content

Inverted SectionList/Flatlist/Flashlist has frame drop #35983

Closed

Description

@devoren

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>
  );

Activity

  1. cl3i550n commented on Jan 26, 2023

    @cl3i550n

    @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.

  2. devoren commented on Jan 26, 2023

    @devoren
    Author

    @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

  3. decisionnguyen commented on Jan 27, 2023

    @decisionnguyen

    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}],
       },
    
  4. devoren commented on Jan 27, 2023

    @devoren
    Author

    @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 :(

  5. devoren commented on Jan 27, 2023

    @devoren
    Author

    @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?

  6. cl3i550n commented on Jan 27, 2023

    @cl3i550n

    @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...

  7. devoren commented on Jan 27, 2023

    @devoren
    Author

    @cl3i550n What version of RN are you using?

  8. cl3i550n commented on Jan 27, 2023

    @cl3i550n

    @cl3i550n What version of RN are you using?

    0.71.1

  9. devoren commented on Jan 27, 2023

    @devoren
    Author

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

  10. cl3i550n commented on Jan 27, 2023

    @cl3i550n

    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!

  11. devoren commented on Jan 27, 2023

    @devoren
    Author

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

  12. IshmamR commented on Feb 4, 2023

    @IshmamR

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

  13. devoren commented on Feb 4, 2023

    @devoren
    Author

    @IshmamR Thank you, i will try

  14. glundgrenm commented on Feb 16, 2023

    @glundgrenm

    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.

  15. brsaylor2 commented on Mar 9, 2023

    @brsaylor2

    possible duplicate of #35350

  16. kelset commented on May 9, 2023

    @kelset
    Contributor

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions