React.memo和useCallback组合使用

1. React.memo 是什么?

React.memo 是一个高阶组件(HOC),它的作用是:"缓存"你的组件

  • 当父组件重新渲染时,React.memo 会**浅层比较(Shallow Compare)**子组件的 props
  • 如果 props 没有发生变化,子组件就不会重新渲染,直接复用上一次的结果。
  • 如果 props 发生了变化,子组件才会重新渲染。

2. 把"普通函数"作为 props 传进去,会发生什么?

假设你有这样的代码:

jsx 复制代码
// ❌ 子组件被 memo 包裹
const Child = React.memo(({ onClick }) => {
  console.log('子组件渲染了');
  return <button onClick={onClick}>点我</button>;
});

function Parent() {
  const [count, setCount] = useState(0);

  // ⚠️ 这是一个普通函数,每次 Parent 渲染都会重新创建
  const handleClick = () => {
    console.log('点击了');
  };

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>增加</button>
      <Child onClick={handleClick} /> {/* 把函数传给了 Child */}
    </div>
  );
}

执行流程:

  1. 点击"增加"按钮,count 变化,Parent 重新渲染。
  2. Parent 重新执行,handleClick 被重新创建(内存地址变了)。
  3. React.memo 比较 Childprops
    • 上一次的 onClick函数A(地址 0x001)。
    • 这一次的 onClick函数B(地址 0x002)。
    • 浅层比较:0x001 === 0x002false
  4. 结论React.memo 认为 props 变了,所以子组件重新渲染

结果 :你用了 React.memo 想优化性能,结果因为传入了"每次新建的函数"导致优化完全失效(子组件依然跟着父组件一起渲染)。


3. 那怎么解决?

如果你希望 React.memo 生效,必须保证传给子组件的函数引用不变

解决方法就是用 useCallback 缓存这个函数:

jsx 复制代码
// ✅ 修复后的代码
function Parent() {
  const [count, setCount] = useState(0);

  // useCallback 保证:只要依赖 [] 不变,handleClick 永远是同一个引用
  const handleClick = useCallback(() => {
    console.log('点击了');
  }, []);

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>增加</button>
      <Child onClick={handleClick} /> {/* 引用不变 ✅ */}
    </div>
  );
}

现在:

  • React.memo 比较两次的 onClick,发现是同一个对象(引用地址相同)。
  • 结论:props 没变 → 子组件不重新渲染,性能优化生效。

4. 类似地,对象和数组也会导致这个问题

jsx 复制代码
// ❌ 传递每次新建的对象,也会让 memo 失效
<Child config={{ theme: 'dark' }} />

// ✅ 使用 useMemo 缓存对象
const config = useMemo(() => ({ theme: 'dark' }), []);
<Child config={config} />

一句话总结

"作为 props 传递给 React.memo 子组件" 就是指:当你把一个引用类型 (函数、对象、数组)传给被 React.memo 包裹的子组件时,如果这个引用在父组件每次渲染时都重新创建,React.memo 的浅层比较会认为 props 变了,导致子组件跟着重新渲染,失去优化意义。

要解决这个问题,你必须用 useCallback (缓存函数)或 useMemo (缓存对象/数组)来保持引用稳定。这也是为什么 useCallbackuseMemo 几乎总是和 React.memo 成对出现的原因。

相关推荐
ℋᙚᵐⁱᒻᵉ鲸落4 小时前
移动端滑动手势冲突:overflow: auto导致外层横向滑动失效
前端·javascript·css·vue.js·html
默_笙5 小时前
🎃 前端学了 Next.js,后端该学啥?NestJS 就是 Node 版的蜜雪冰城
前端·javascript
前端snow6 小时前
ai agent --- 实现 openclaw 定时间效果
前端
码云之上7 小时前
换模型之后,Chatbot 为什么要自己做 compact?
前端·agent·前端工程化
星栈7 小时前
自定义 UI-UX-Pro-Max 的 CSV 知识库,把 AI 生成的后台拉回行业该有的样子
前端·agent·weui
研☆香7 小时前
简单的图片上传 删除 预览
前端
ITresearchGuest7 小时前
我用 AI 一小时写了一个世界杯数据可视化平台|前端 VibeCoding 初体验
前端·人工智能·信息可视化
慧一居士8 小时前
Vite项目中使用Less步骤,详细使用示例
前端·css
花间相见9 小时前
【LangChain组件03】—— LangChain Agents 执行与状态:工作流程与状态管理实战
java·前端·langchain
kyriewen9 小时前
面试官让我用 AI 重构一个 8 年陈的 React 组件——他说他不看代码,只看我会不会拆
前端·javascript·面试