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

FlatList大数据量时点击复选框状态更新卡顿,如何优化性能?

React Native FlatList 大量数据下点击Checkbox卡顿问题解决

问题描述

当FlatList数据量达数百条(如700条)时,点击列表项的Checkbox会出现严重卡顿:首次点击耗时约1秒,后续每次点击耗时递增20%,最终稳定在2.5秒左右。经排查,性能瓶颈出现在contactPhoneNumberList2状态变更后的全量重渲染。

根本原因

每次状态更新后,FlatList的所有列表项都会重新执行_renderItem函数,且每个列表项都通过find方法遍历选中列表判断状态,同时没有任何组件记忆化处理,导致大量不必要的计算和渲染操作,随着选中项增加,耗时逐步累积。

优化方案

1. 用Set存储选中状态,提升查找效率

将选中的手机号列表从数组改为Set,has方法的时间复杂度为O(1),远优于数组的find(O(n)),同时减少状态更新时的数组拷贝开销。

2. 抽离子组件并使用React.memo缓存

把列表项抽成独立组件,用React.memo包裹,只有当组件的props(如item、isSelected、onPress)变化时才会重渲染,避免全量列表项跟着父组件状态变更而重渲染。

3. 使用函数式状态更新+useCallback缓存事件

避免依赖旧状态的引用,确保状态更新的准确性;同时用useCallback缓存点击事件,避免子组件因函数引用变化触发不必要的重渲染。

修改后的完整代码

import React, { useState, useCallback } from 'react';
import { FlatList } from 'react-native';
import { ListItem } from '@rneui/themed'; // 根据实际使用的UI库调整

// 抽离列表项子组件,用React.memo缓存
const ContactItem = React.memo(({ item, isSelected, onPress }) => {
  return (
    <ListItem>
      <ListItem.CheckBox checked={isSelected} onPress={onPress} />
      <ListItem.Content>
        <ListItem.Title>{item.mobileNo}</ListItem.Title>
      </ListItem.Content>
    </ListItem>
  );
});

const TestScreen = () => {
  // 构建测试数据集,实际场景从Redux获取
  const contactList = Array.from({ length: 700 }, (_, i) => ({ mobileNo: i.toString() }));

  // 用Set存储选中的手机号,提升查找效率
  const [selectedNumbers, setSelectedNumbers] = useState(new Set());

  // 用useCallback缓存点击事件,避免子组件重复接收新函数
  const handlePress = useCallback((item) => {
    setSelectedNumbers(prev => {
      const newSet = new Set(prev);
      if (newSet.has(item.mobileNo)) {
        newSet.delete(item.mobileNo);
      } else {
        newSet.add(item.mobileNo);
      }
      return newSet;
    });
  }, []);

  const renderItem = ({ item }) => {
    const isSelected = selectedNumbers.has(item.mobileNo);
    return (
      <ContactItem
        item={item}
        isSelected={isSelected}
        onPress={() => handlePress(item)}
      />
    );
  };

  return (
    <FlatList
      data={contactList}
      keyExtractor={(item) => item.mobileNo} // mobileNo唯一,无需额外拼接索引
      renderItem={renderItem}
      initialNumToRender={10}
      maxToRenderPerBatch={10}
      windowSize={10}
    />
  );
};

export default TestScreen;

额外优化提示

  • 若数据来自Redux,使用createSelector创建记忆化的选择器,避免父组件因Redux状态微小变化触发重渲染。
  • 自定义ListItem组件时,避免在render函数内部创建新函数或对象,确保props的稳定性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 12:18:27