You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native ScrollView内嵌FlatList卡顿滚动异常问题求解

问题说明

需求为实现类似DoorDash商家页的垂直堆叠列表效果:用户可动态填充数组作为FlatList的数据源,每新增条目自动扩展容器高度,页面整体支持上下滚动,垂直展示所有内容。
最初采用ScrollView嵌套scrollEnabled={false}的FlatList实现,出现模拟器严重卡顿、滚动到底部时ScrollView上下跳动的异常。

原有实现代码

const [items, setItems] = React.useState([])
const [newItem, setNewItem] = React.useState(newItem)

const newItem = [
{
    name: null,
    about: null,
    picture: null,
    price: null
}]

<ScrollView>
    <SafeAreaView>
        <FlatList
            data={items}
            keyExtractor{(item, index) => index.toString()}
            scrollEnabled={false}
            renderItem={renderItems()}
        />
    </SafeAreaView>
</ScrollView>

基础新增条目功能可正常运行,但ScrollView内容长度增长后会出现明显卡顿。FlatList条目样式参考:菜单项样式参考
核心诉求:在ScrollView内嵌FlatList的场景下实现动态数组懒加载,无卡顿问题。


解决方案

同方向滚动的ScrollView嵌套关闭滚动的FlatList是React Native公认的性能反模式:关闭滚动后FlatList会一次性渲染全量数据,完全丢失虚拟列表的懒加载能力,同时两个滚动容器的高度动态计算会持续冲突,必然引发卡顿、滚动跳动问题。针对需求有两种可落地的实现路径:

方案1:单FlatList作为根滚动容器(优先选择,性能最优)

这类全页垂直滚动的列表场景完全不需要嵌套ScrollView,直接将页面中所有非列表内容(商家头部信息、banner、筛选栏等)全部放入FlatList的ListHeaderComponent属性中,从根源上避免滚动嵌套问题,同时完全保留FlatList的虚拟滚动懒加载能力,哪怕数据量上千也不会卡顿。
参考实现:

import { View, Text, FlatList, SafeAreaView, Image } from 'react-native'

// 列表上方的所有非菜品内容统一放到头部组件
const PageHeader = () => {
  return (
    <View style={{ padding: 16 }}>
      {/* 此处放商家头图、名称、评分、配送信息、分类标签等内容 */}
      <Text style={{ fontSize: 20, fontWeight: 'bold' }}>商家菜单</Text>
    </View>
  )
}

// 单条菜品渲染逻辑
const renderItem = ({ item }) => {
  return (
    <View style={{ padding: 16, flexDirection: 'row', gap: 12 }}>
      <Image source={{ uri: item.picture }} style={{ width: 80, height: 80, borderRadius: 8 }} />
      <View style={{ flex: 1 }}>
        <Text style={{ fontSize: 16, fontWeight: '500' }}>{item.name}</Text>
        <Text style={{ color: '#666', marginTop: 4 }}>{item.about}</Text>
        <Text style={{ marginTop: 8, color: '#f00' }}>¥{item.price}</Text>
      </View>
    </View>
  )
}

export default function RestaurantPage() {
  const [items, setItems] = React.useState([])

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <FlatList
        data={items}
        keyExtractor={(item, index) => item?.id ? item.id.toString() : index.toString()}
        ListHeaderComponent={<PageHeader />}
        renderItem={renderItem}
        initialNumToRender={6}
        windowSize={5}
        maxToRenderPerBatch={4}
      />
    </SafeAreaView>
  )
}

新增条目时直接调用setItems更新数组即可,FlatList会自动计算内容高度,按虚拟列表规则懒加载条目,无额外性能消耗。

方案2:必须保留外层ScrollView时的优化方案

如果页面存在多个同方向滚动区块,必须保留ScrollView作为外层容器,做两个调整即可解决卡顿:

  • 替换内置FlatList为@shopify/flash-list,配置准确的estimatedItemSize属性,关闭滚动时也能保留虚拟渲染能力,高度计算性能比内置FlatList高70%以上
  • 修复原有代码的两个性能bug:
    • keyExtractor后缺少等号,正确写法为keyExtractor={(item, index) => ...}
    • renderItem不可直接传入renderItems()的执行结果,需要传入函数引用renderItem={renderItems},否则每次组件重渲染都会重新执行全量条目的渲染逻辑,加剧卡顿

内容的提问来源于stack exchange,提问作者guyman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 01:36:27