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

React Native中FlatList内TouchableOpacity响应缓慢优化咨询

问题

通过Spotify API获取音乐流派列表,使用React Native的FlatList渲染,每个列表项由TouchableOpacity包裹Text组件实现。通过setState存储已选中的流派,借助hasSelected函数判断流派是否已选中。当前功能正常,但选中项的背景填充需约2秒才能完成,如何优化该性能问题?

现有代码

FlatList组件代码:

<FlatList
  w="full"
  data={genres}
  numColumns={3}
  ItemSeparatorComponent={() => <View className="p-1"></View>}
  renderItem={({ item }) => (
    <TouchableOpacity
      onPress={() => setMySelect((prev) => [...prev, item])}
      className="px-2"
    >
      <Text
        className={`rounded-full border font-kanit text-center  py-0 px-3 ${hasSelected(item, mySelect) ? "bg-tertiary text-gray-100 border-transparent" : "text-danube-400 border-danube"} `}
      >
        {item}
      </Text>
    </TouchableOpacity>
  )}
/>

hasSelected函数(utils.tsx):

export const hasSelected = (item: string, mySelect: string[]) => {
  return mySelect.includes(item);
};

优化方案

1. 用Set替代数组存储选中项,提升查找效率

数组的includes方法是O(n)时间复杂度,当选中流派数量增加时,每次判断都会遍历整个数组,拖慢FlatList重渲染速度。改用Set存储选中项,has方法为O(1)复杂度,能大幅缩短判断耗时。

修改状态初始化与更新逻辑:

// 初始化状态为Set
const [mySelect, setMySelect] = useState(new Set<string>());

// 点击事件处理(支持选中/取消选中,可按需调整)
onPress={() => setMySelect(prev => {
  const newSet = new Set(prev);
  newSet.has(item) ? newSet.delete(item) : newSet.add(item);
  return newSet;
})}

同步修改hasSelected函数:

export const hasSelected = (item: string, mySelect: Set<string>) => {
  return mySelect.has(item);
};

2. 给FlatList添加keyExtractor,减少不必要的组件重建

FlatList默认用数组索引作为key,当数据更新时容易触发无意义的组件卸载与重建。指定唯一的keyExtractor,让React精准识别需要更新的列表项:

<FlatList
  w="full"
  data={genres}
  numColumns={3}
  keyExtractor={(item) => item} // 流派名称唯一,直接作为key
  ItemSeparatorComponent={() => <View className="p-1"></View>}
  renderItem={({ item }) => (
    // 原有renderItem内容
  )}
/>

3. 抽离列表项组件并使用React.memo,避免冗余重渲染

将列表项抽为独立组件,通过React.memo缓存未变化的组件,仅当选中状态或内容改变时才重新渲染:

// 抽离的列表项组件
const GenreItem = React.memo(({ item, isSelected, onPress }) => (
  <TouchableOpacity
    onPress={onPress}
    className="px-2"
  >
    <Text
      className={`rounded-full border font-kanit text-center py-0 px-3 ${isSelected ? "bg-tertiary text-gray-100 border-transparent" : "text-danube-400 border-danube"} `}
    >
      {item}
    </Text>
  </TouchableOpacity>
));

// FlatList中使用
<FlatList
  // 其他属性
  renderItem={({ item }) => (
    <GenreItem
      item={item}
      isSelected={mySelect.has(item)}
      onPress={() => setMySelect(prev => {
        const newSet = new Set(prev);
        newSet.has(item) ? newSet.delete(item) : newSet.add(item);
        return newSet;
      })}
    />
  )}
/>

4. 提取ItemSeparatorComponent为常量,避免重复创建函数

原代码中ItemSeparatorComponent是render时创建的匿名函数,每次渲染都会生成新实例,触发不必要的重渲染。提取为固定常量:

// 提取为常量组件
const ItemSeparator = () => <View className="p-1"></View>;

// FlatList中使用
<FlatList
  // 其他属性
  ItemSeparatorComponent={ItemSeparator}
  // ...
/>

内容的提问来源于stack exchange,提问作者José Carlos

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 09:31:31