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

如何在更新父组件对象数组状态时仅重渲染目标ItemCard组件?

React.memo缓存组件后仍全部重渲染的解决办法

问题场景

我尝试用memo缓存ItemCard组件,期望调用setItems()更新父组件ItemList的对象数组状态时,仅被修改的ItemCard触发重渲染,但点击按钮后所有ItemCard均出现了重渲染。

父组件ItemList代码:

const ItemList = () => {
  const [items, setItems] = useState([
    { id: 1, count: 5 },
    { id: 2, count: 7 },
    { id: 3, count: 2 },
  ]);

const updateItemCount = (itemId, add) => {
  const updatedItems = items.map((item) => {
    const { id, count } = item;

    if (id === itemId) {
      return { ...item, count: add ? count + 1 : count - 1 };
    }
    return item;
  });

  setItems(updatedItems);
};

  return (
    <div>
      {items.map((item) => (
        <ItemCard {...item} updateItemCount={updateItemCount} />
      ))}
    </div>
  );
};

子组件ItemCard代码:

import { memo } from 'react';

const ItemCard = memo(({id, count, updateItemCount}) => {

console.log("re-rendered", id)

  return (
    <button onClick={() => updateItemCount(id, true)}></button>
  );
});

问题原因

核心问题在于updateItemCount函数:每次父组件ItemList重渲染时,这个函数都会被重新创建,导致传递给每个ItemCard的updateItemCount prop都是全新的引用。memo默认采用浅比较props,只要有一个prop的引用发生变化,就会判定为props更新,触发子组件重渲染。

即便只有一个item对象被修改,其他未修改的item引用没有变化,但因为updateItemCount的引用变了,所有ItemCard都会触发重渲染。

解决方案

1. 用useCallback缓存updateItemCount函数

使用useCallback包裹函数,同时采用函数式更新state,避免依赖外部的items变量,确保函数引用稳定。

修改后的父组件代码:

import { useState, useCallback } from 'react';

const ItemList = () => {
  const [items, setItems] = useState([
    { id: 1, count: 5 },
    { id: 2, count: 7 },
    { id: 3, count: 2 },
  ]);

  // 用useCallback缓存函数,函数式更新state避免依赖外部items
  const updateItemCount = useCallback((itemId, add) => {
    setItems(prevItems => prevItems.map(item => {
      if (item.id === itemId) {
        return { ...item, count: add ? item.count + 1 : item.count - 1 };
      }
      return item;
    }));
  }, []); // 依赖项为空,setItems是React提供的稳定引用

  return (
    <div>
      {items.map((item) => (
        {/* 必须添加key属性,这是React列表渲染的规范 */}
        <ItemCard key={item.id} {...item} updateItemCount={updateItemCount} />
      ))}
    </div>
  );
};

2. 保留memo的浅比较逻辑

子组件的memo无需额外修改,现在updateItemCount引用稳定后,未修改的ItemCard的所有props(id、count、updateItemCount)都与上一次渲染一致,memo会判定props未变化,跳过重渲染。

优化后的子组件(可补充按钮文本方便测试):

import { memo } from 'react';

const ItemCard = memo(({ id, count, updateItemCount }) => {
  console.log("re-rendered", id);
  return (
    <button onClick={() => updateItemCount(id, true)}>
      数量:{count} +1
    </button>
  );
});

export default ItemCard;

效果验证

修改完成后,点击任意ItemCard的按钮,只有该组件的控制台会打印re-rendered日志,其他未修改的组件不会触发重渲染,达到预期效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 08:28:38