React中如何使用useMemo对Array.map()生成的每个元素做缓存?
解决方案
最推荐的实现方式是将单个列表项抽离为独立组件,配合React.memo实现单元素级别的缓存,只有发生变更的对应项才会触发重渲染。
方案1:抽离React.memo包裹的列表项组件(生产环境首选)
- 先定义独立的列表项组件,用
React.memo包裹,默认会对props做浅比较判断是否需要重渲染:
import React from 'react' // 仅当props发生变化时才会重渲染该组件 const UserItem = React.memo(({ user }) => { return <p>{user.name}</p> })
- 父组件遍历渲染时传入对应的props,同时必须配置唯一且稳定的key:
// 这里的key不要使用数组下标,建议使用用户id等业务唯一标识 users.map((user) => ( <UserItem key={user.id} user={user} /> ))
如果你的user对象存在引用变化但实际业务字段未变更的场景,可以给React.memo传入第二个自定义比较函数,自己控制重渲染逻辑:
const UserItem = React.memo(({ user }) => { return <p>{user.name}</p> }, (prevProps, nextProps) => { // 返回true代表props无变化,不需要重渲染;返回false代表需要重渲染 return prevProps.user.id === nextProps.user.id && prevProps.user.name === nextProps.user.name })
方案2:用useMemo缓存整个列表(轻量场景可选)
如果不想抽离组件,也可以把整个遍历逻辑包裹在useMemo中,依赖设置为users数组,只要数组引用不变、内部元素引用不变,整个列表都不会重新生成:
import { useMemo } from 'react' // 组件内逻辑 const userList = useMemo(() => { return users.map((user) => ( <p key={user.id}>{user.name}</p> )) }, [users]) // 渲染时直接使用缓存的列表 return <div>{userList}</div>
关键注意事项
- 所有列表项必须配置唯一且稳定的key,禁止使用数组下标作为key,否则元素顺序变化时会直接导致缓存失效,甚至出现渲染错乱。
- 更新
user对象时请使用不可变更新方式,不要直接修改原对象的属性,否则浅比较会判断props无变化,不会触发对应项的重渲染。 - 若存在列表筛选、排序等场景,优先使用方案1的独立memo组件,缓存效率远高于方案2。
内容的提问来源于stack exchange,提问作者Daniele Molinari
相关产品推荐
相关产品推荐

