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

React Native FlatList已Memo化仍全量重渲染的优化问题

React Native FlatList 重渲染问题解决思路

问题情况

我碰到React Native里FlatList的重渲染问题:父组件的selectedNoteId state变化时,哪怕已经用memo封装了FlatList,所有列表项还是会跟着重渲染。我只想让被点击的那个TouchableOpacity对应的列表项重渲染,就算给memo传恒为true的比较函数,问题还是存在。

相关代码:

export default ({ notes }: Props) => {
  const noteSrv = new noteService()

  const [selectedNoteId, setSelectedNoteId] = useState(NaN)

  const noteSelected = (note: Note) => {
    setSelectedNoteId(note.id)
  }

  const ListMemo = memo(function ({
    notes,
    isSelected,
  }: {
    notes: Note[]
    isSelected: boolean
  }) {
    return (
      <FlatList
        data={notes}
        renderItem={(i) => (
          <ListItem
            isSelected={false}
            note={i.item}
            noteSelected={noteSelected}
          />
        )}
        keyExtractor={(item) => item.id.toString()}
      ></FlatList>
    )
  })

  return  //whatever
}

问题根源

  1. ListMemo定义位置错误:把ListMemo放在父组件内部,每次父组件重渲染都会创建一个全新的组件类型,memo的缓存完全失效。
  2. noteSelected函数无缓存:父组件state变化时,noteSelected会重新生成,作为props传给ListItem后,即使ListItem用了memo,也会因为函数引用变化触发重渲染。
  3. isSelected逻辑错误:给所有ListItem传的isSelected都是false,完全没利用selectedNoteId判断当前项是否选中,逻辑本身不成立。

修复步骤及代码

1. 封装ListItem并缓存回调

先给ListItem加上memo,避免不必要的重渲染:

// 单独封装ListItem并使用memo
const ListItem = memo(({ note, isSelected, noteSelected }: {
  note: Note
  isSelected: boolean
  noteSelected: (note: Note) => void
}) => {
  return (
    <TouchableOpacity onPress={() => noteSelected(note)}>
      {/* 根据isSelected渲染选中样式,比如背景色变化 */}
      <Text>{note.title}</Text>
    </TouchableOpacity>
  )
})

2. 把ListMemo移到父组件外部

确保组件类型稳定,让memo能正常生效:

// 移到父组件外部,避免每次父渲染生成新组件
const ListMemo = memo(function ({
  notes,
  selectedNoteId,
  noteSelected,
}: {
  notes: Note[]
  selectedNoteId: number | typeof NaN
  noteSelected: (note: Note) => void
}) {
  return (
    <FlatList
      data={notes}
      renderItem={(i) => (
        <ListItem
          // 正确判断当前项是否选中
          isSelected={i.item.id === selectedNoteId}
          note={i.item}
          noteSelected={noteSelected}
        />
      )}
      keyExtractor={(item) => item.id.toString()}
    />
  )
})

3. 父组件优化

用useCallback缓存noteSelected,避免函数引用频繁变化:

export default ({ notes }: Props) => {
  const noteSrv = new noteService()

  const [selectedNoteId, setSelectedNoteId] = useState(NaN)

  // 用useCallback缓存函数,依赖项只加setSelectedNoteId(React的state setter是稳定引用)
  const noteSelected = useCallback((note: Note) => {
    setSelectedNoteId(note.id)
  }, [setSelectedNoteId])

  // 如果notes是父组件传来的可变数组,建议用useMemo缓存
  const cachedNotes = useMemo(() => notes, [notes])

  return (
    <ListMemo 
      notes={cachedNotes} 
      selectedNoteId={selectedNoteId} 
      noteSelected={noteSelected} 
    />
  )
}

额外提醒

  • 不要在组件内部定义另一个组件,否则每次渲染都会生成新组件,memo完全起不到作用。
  • 如果notes数组会频繁更新,一定要用useMemo缓存,避免因为数组引用变化触发FlatList的重渲染。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 05:00:35