React Native列表滚动卡顿怎么优化?

Mr-斐然 阅读 84

我在用FlatList渲染一个商品列表,数据大概有200条左右,但一滚动就明显卡顿,FPS掉得很厉害。已经加了keyExtractor和initialNumToRender,还是没改善。

是不是 renderItem 里组件太重了?我里面用了Image和Text,还套了几层View。下面是我现在的写法:

const renderItem = ({ item }) => (
  <View style={{ padding: 16 }}>
    <Image source={{ uri: item.image }} style={{ width: 80, height: 80 }} />
    <Text>{item.title}</Text>
    <Text>{item.price}</Text>
  </View>
);

有没有什么办法能让列表滑动更流畅?比如该不该用React.memo或者优化图片加载?

我来解答 赞 4 收藏
二维码
手机扫码查看
2 条解答
Top丶瑞珺
你这个问题太常见了,200条数据本身不该卡成这样的。让我帮你分析一下:

先说renderItem的问题

你现在的写法每次滚动都会重新创建这些组件,React.memo必须用上。最简单的方式是把renderItem改成独立的组件,然后用memo包起来:

const ProductItem = React.memo(({ item }) => (
<View style={{ padding: 16, flexDirection: 'row' }}>
<Image
source={{ uri: item.image }}
style={{ width: 80, height: 80 }}
// 加上这几个属性会好很多
resizeMode="cover"
/>
<View style={{ marginLeft: 12, flex: 1 }}>
<Text numberOfLines={2>{item.title}</Text>
<Text>{item.price}</Text>
</View>
</View>
));

// FlatList那边
<FlatList
data={products}
renderItem={({ item }) => <ProductItem item={item} />}
keyExtractor={item => item.id}
initialNumToRender={10}
maxToRenderPerBatch={10}
windowSize={10}
removeClippedSubviews={true} // 这个很重要
getItemLayout={(data, index) => ({
length: 112, // 每个item的高度,算好填进去
offset: 112 * index,
index,
})}
/>


关于图片

如果图片加载慢,也会导致卡顿。可以考虑几个方案:给Image加个默认图或者loading状态、或者用react-native-fast-image这个库来缓存图片,会比原生Image快很多。

减少View嵌套

你说套了几层View,这个也有影响。你现在代码里其实嵌套不多,但如果父组件那边还有其他包装,能省则省。

关于getItemLayout

这个一定一定要加!它让FlatList不用每次去算每个item的高度,直接按索引跳到对应位置,滚动流畅度提升很明显。你需要提前把item的高度算出来传进去。

这几个一起用的话,200条数据流畅滚动基本没问题。你先试试,有问题再贴代码进来。
点赞
2026-03-14 11:19
丽苹
丽苹 Lv1
200条数据就卡顿确实有点说不过去,你renderItem里东西虽然不轻,但也不至于这么离谱。主要问题应该是每次滚动都重新渲染了子组件。

先说最直接有效的方案:用 React.memo 包装你的 Item 组件。

const ListItem = React.memo(({ item }) => (



{item.title}
{item.price}


));

const renderItem = ({ item }) => ;

这样只有 item 的引用变化时才重新渲染,避免了每次滚动都触发 renderItem。

然后图片这块,如果你没做缓存处理,Image 组件每次渲染都会发起请求。生产环境建议用 react-native-fast-image 这个库,它带磁盘缓存,比原生 Image 强太多。

const ListItem = React.memo(({ item }) => (

source={{ uri: item.image }}
style={{ width: 80, height: 80 }}
/>

{item.title}
{item.price}


));

还有几个 FlatList 的参数可以调一下:

data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
getItemLayout={(data, index) => ({
length: 112, // 你的item高度
offset: 112 * index,
index,
})}
maxToRenderPerBatch={10}
windowSize={10}
removeClippedSubviews={true}
/>

getItemLayout 是最重要的,加上这个 FlatList 就不用每次算高度了,能提升明显。maxToRenderPerBatch 和 windowSize 控制渲染批次,可以减少首屏渲染压力。

至于你问的该不该用 memo,答案是:该用。只要你的 Item 组件是独立的,都建议用 memo 包一下。200条数据本身不大,优化完应该能跑满60fps。
点赞
2026-03-12 23:12