如何正确使用useMemo/React.memo优化对象数组列表,避免单条编辑时全量重渲染
问题根因梳理
你当前遇到的全列表重渲染问题,是代码里多个细节错误共同导致的,和Memo API的使用逻辑错误直接相关:
- Child组件没有实际包裹React.memo:你提到给卡片加了React.memo,但提供的代码里Child组件导出时没有用
React.memo(Child)包裹,自然不会做props对比跳过渲染。 - 函数引用不稳定:
- Child组件内的
onClickPostLike对应的useCallback没有加依赖数组,每次Child渲染都会生成全新的函数引用,就算加了React.memo也会因为props变化触发重渲染。 - usePostLike(你代码里实际导出命名是usePressLike,命名不一致)中的
pressLike对应的useCallback依赖不全,用到的toggleIsSending、asyncCurrentData没有加入依赖数组,会导致postLike函数引用意外变化。
- Child组件内的
- 全局状态订阅不合理:LikeButton组件直接订阅了全局的
isSendingLike状态,这个状态一旦变化,所有列表项的LikeButton都会触发重渲染,和自身props是否变化无关。 - 无效的useMemo使用:你在Parent里写的
memoizedListData完全没有作用,只是对listData做了一层无意义的浅拷贝,依赖项就是listData本身,和直接遍历listData没有任何区别,反而增加了不必要的计算开销。 - 代码Bug:LikeButton的入参声明错误,你传入的props是
liked,但入参里写的是like,导致状态判断异常。
优化步骤(最优方案)
不需要做的操作
- 不需要缓存整个列表:父组件订阅了全量的
getCardList状态,只要列表有任意一条数据更新,父组件必然重渲染,这是正常行为,不需要强制阻止父组件重渲染,只要保证未更新的子组件跳过渲染即可。 - 不需要单独缓存单条子项:只要保证子组件props引用稳定,React.memo的浅对比就足够生效。
需要做的操作
- 给Child组件包裹React.memo,默认做浅比较即可:
export default React.memo(Child)
- 稳定所有函数引用:
- 修复Child内的useCallback,补充完整依赖:
const onClickPostLike = useCallback(() => { postLike(id) }, [postLike, id]) // 只有postLike或id变化时才生成新函数- 修复usePostLike内useCallback的依赖,确保postLike引用稳定:
const pressLike = useCallback( async (id) => { // 原有逻辑不变 }, [setList, toggleIsSending, asyncCurrentData] // 把所有用到的内部变量都加入依赖,Recoil返回的setter、useRecoilCallback本身都是引用稳定的,所以pressLike的引用永远不会变 ) - 优化全局状态订阅,避免全局状态触发全量子组件更新:
把全局的isSendingLike从布尔值改成正在点赞的卡片ID集合,LikeButton只订阅和自身ID相关的状态,比如:
// 原来的全局状态是boolean,改成Set类型 const isSending = useRecoilValue(isSendingLikeSet) const currentIsSending = isSending.has(id) // 只判断当前ID是否在点赞中
或者直接把isSending状态下放到每条卡片数据里,只有更新的那条数据的状态会变化,其他子组件不受影响。
4. 删掉Parent里无效的memoizedListData,直接遍历listData即可。
5. 修复LikeButton的入参错误:
const LikeButton = ({ onClickPostLike, liked, likedNum }) => { // 把like改成liked
核心疑问解答
列表场景的Memo优化最优逻辑是:
- 父组件不需要做列表缓存,只要保证传给子组件的props(尤其是函数、对象类型)引用稳定即可
- 子组件用
React.memo包裹,依赖浅对比判断是否跳过渲染 - 子组件内部不要订阅和自身无关的全局状态,避免props没变的情况下被全局状态触发重渲染
父组件重渲染是正常的,它本身的渲染开销极低,只要未更新的子组件都跳过了渲染,性能就不会有问题。
内容的提问来源于stack exchange,提问作者gwrik09
相关产品推荐
相关产品推荐

