十倍提升React Native中FlatList性能之removeClippedSubviews底层原理

627 阅读3分钟

什么是FlatList的removeClippedSubviews属性

FlatList的removeClippedSubviews属性是React Native中的一个布尔型属性,它可以指示React Native组件是否应该将超出屏幕外的视图从渲染树中删除。如果设置为true,则只有屏幕内部可见的视图才会在渲染树中保留。

removeClippedSubviews 属性是 FlatList 组件的一个重要特性,它可以提升 FlatList 的渲染性能,简单来说,它会将列表中正在被屏幕裁剪的子视图移除,从而减少渲染开销。

当 FlatList 组件滚动时,removeClippedSubviews 属性会将滚出屏幕外的列表项移除,这样就可以减少渲染开销,可以有效地减少不在屏幕上可见的列表项所占用的内存,从而提高渲染性能,减少内存消耗。

底层原理

removeClippedSubviews 使用了虚拟列表(Virtualized List)技术,它通过跟踪用户的滚动位置来动态地渲染列表,并且可以有效地减少不在屏幕上可见的列表项所占用的内存。、

removeClippedSubviews属性的底层原理是结合使用React Native中的UIManagerView类中的onLayout方法。UIManager中的measureInWindow方法可以获取视图距离屏幕顶部和左边的距离,以及视图的宽度和高度。View类中的onLayout方法会在每次视图的位置被更新时被调用。当removeClippedSubviews属性被设置为true时,React Native将使用以上方法检查视图是否超出屏幕范围。如果视图超出屏幕范围,则将其从渲染树中删除,从而提高性能。

注意的事项以及如何避免

在使用 removeClippedSubviews 属性时,需要注意以下几点:

  1. 如果列表中的项目在滚动时有显著的变化,例如有滚动动画,则不建议使用 removeClippedSubviews 属性
  2. 如果列表中的项目内容较复杂,可能会有较高的渲染开销,这时也不建议使用 removeClippedSubviews 属性,因为它会移除正在滚动的项目,从而影响渲染性能。
  3. 如果列表中的项目内容比较简单,那么使用 removeClippedSubviews 属性可以大大提升渲染性能。
  4. 在 iOS系统中避免使用
  5. 确保列表中的子组件都有固定的高度,因为不固定的高度会导致 removeClippedSubviews 的性能降低。
  6. 不要使用过多的图片,因为图片会导致 removeClippedSubviews 的性能降低。
  7. 使用唯一的 key 属性,确保每一个列表项都有一个唯一的 key,这样可以有效地提高 removeClippedSubviews 的性能。

示例1:在滚动动画中不使用 removeClippedSubviews 属性

const MyFlatList = ({data}) => {
  const [scrollY, setScrollY] = useState(0);

  return (
    <FlatList
      data={data}
      removeClippedSubviews={false}  // 不使用 removeClippedSubviews 属性
      onScroll={(e) => setScrollY(e.nativeEvent.contentOffset.y)}
      scrollEventThrottle={16}
      scrollIndicators={false}
      scrollY={scrollY}
    />
  );
};

示例2:在iOS系统中不使用 removeClippedSubviews 属性

removeClippedSubviews: Platform.OS==='android'

示例3:使用key以及固定高度

import { Flatlist } from 'react-native';

const MyFlatlist = ({data}) => {
  return (
    <Flatlist 
      data={data}
      removeClippedSubviews={true}
      keyExtractor={(item, index) => `${item.id}-${index}`}
      renderItem={({ item }) => (
        <View style={{height:50}}>
          <Text key={item.id}>{item.name}</Text>
        </View>
      )}
    />
  );
}

上面代码中,我们将 removeClippedSubviews 设置为 true,同时为每一个列表项设置一个唯一的 key,这样可以有效地减少不在屏幕上可见的列表项所占用的内存,同时确保每一个列表项都有一个固定的高度,从而有效地提高 removeClippedSubviews 的性能。

欢迎讨论咨询