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

React函数组件如何防止子组件产生额外重复渲染?

问题根因

React.memo 通过props浅比较判断是否跳过子组件重渲染:

  • 类组件中clickHandler是定义在类实例上的箭头函数,组件重渲染不会改变类实例,因此this.clickHandler的引用始终固定,传给CounterButton的onClick prop每次比较结果都相同,按钮不会重复渲染。
  • 函数组件每次渲染都会完整执行函数体,普通写法定义的clickHandler每次渲染都会生成全新的函数引用,浅比较判定props变化,就会触发按钮重渲染。

你之前用useCallback包裹没生效的原因是:更新状态时直接读取了闭包中的counter值,必须把counter加入useCallback的依赖数组,每次counter变化时缓存的函数就会失效生成新引用,依然会触发子组件重渲染。

修复方案

使用useState提供的函数式更新写法,在更新状态时基于前一个状态计算新值,不需要在回调中依赖外部的counter变量,这样useCallback的依赖数组可以设为空,缓存的函数引用全程不会变化,就能达到和类组件完全一致的渲染表现。

修改后的FunctionComponent代码:

import React, { useCallback } from 'react';

function FunctionComponent() {
  const [counter, setCounter] = React.useState(0);

  const clickHandler = useCallback(() => {
    console.log(">>> FunctionComponent: button clicked <<< ")
    // 函数式更新,不依赖外部counter变量
    setCounter(prev => prev + 1);
  }, []); // 依赖数组为空,函数引用永久缓存

  console.log('---FunctionComponent render---')
  return <>
    <CounterButton name="FunctionComponent" onClick={clickHandler} />
    <CounterDisplay name="FunctionComponent" counter={counter} />
  </>
}

修改后点击按钮的控制台输出和类组件完全一致,不会再触发CounterButton的重复渲染:

>>> FunctionComponent: button clicked <<< 
---FunctionComponent render---
Counter Display Rendered
补充说明

如果遇到更复杂的回调逻辑,不想使用函数式更新,也可以用useRef保存需要的状态值绕开闭包依赖,但对于当前计数器的场景,函数式更新是最简洁、官方推荐的写法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 10:18:30