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

如何通过回调避免父组件状态变更时子组件重复渲染?

解决React父组件更新时子组件过度重渲染的问题

嘿,我来帮你搞定这个子组件频繁重渲染的问题!你已经用了useCallback来稳定deleteUser的引用,这一步做的很对,但还需要给子组件加一层“防护”,让它在props没变化的时候跳过重渲染。

核心问题:默认情况下子组件会跟着父组件重渲染

React的默认行为是,当父组件状态更新重渲染时,所有子组件都会跟着重渲染——哪怕子组件的props根本没变化。你现在的User组件就是这样,哪怕某个用户的数据和回调函数都没变,只要父组件的users数组更新,它还是会重新渲染一次。

解决方案:用React.memo包裹子组件

React.memo是一个高阶组件,它会帮我们缓存子组件的渲染结果。当组件的props和上一次渲染时的props做浅比较后没有变化,就直接复用之前的渲染结果,不会触发新的渲染。

只需要把你的User组件用React.memo包裹起来就行,修改后的代码如下:

const App = () => {
  const [users, setUsers] = useState([
    { id: 1, name: "Cory" },
    { id: 2, name: "Meg" },
    { id: 3, name: "Bob" }
  ]);

  const deleteUser = useCallback(id => {
    setUsers(users => users.filter(user => user.id !== id));
  }, []);

  const renderUser = user => {
    return <User key={user.id} user={user} onClick={deleteUser} />;
  };

  return (
    <div>
      <h1>Users</h1>
      <ul>{users.map(renderUser)}</ul>
    </div>
  );
};

// 用React.memo包裹User组件
const User = React.memo(props => {
  const onDeleteClick = () => {
    props.onClick(props.user.id);
  };

  console.log(`${props.user.name} just rendered`);

  return (
    <li>
      <input type="button" value="Delete" onClick={onDeleteClick} />
      {props.user.name}
    </li>
  );
});

为什么这样有效?

  1. 你已经用useCallback让deleteUser的引用保持稳定——它的依赖是空数组,所以只会在组件初始化时创建一次,后续不会因为父组件重渲染而改变。
  2. 当你删除某个用户时,父组件的users数组更新,但未被删除的用户对象的引用还是原来的(因为filter返回的新数组里,保留的元素是原数组的引用)。
  3. React.memo会对比User组件的user和onClick props,发现没变化的话,就不会触发重渲染——只有被删除的那个用户对应的User组件会被卸载,其他的都不会重新渲染。

额外说明

如果你的user对象是会被重新创建的(比如父组件每次都生成新的对象实例),那浅比较可能会失效,这时候可以给React.memo传第二个参数,自定义props的比较逻辑:

const User = React.memo((props) => {
  // 组件内容
}, (prevProps, nextProps) => {
  // 自定义比较逻辑,返回true表示不需要重渲染
  return prevProps.user.id === nextProps.user.id && prevProps.onClick === nextProps.onClick;
});

不过在你当前的代码场景里,这个额外的比较函数是不需要的,浅比较就足够了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 23:27:31