如何使用 useMemo 或 useCallback 来避免 Context 使用中因父组件的渲染而导致子组件不必要的重复渲染

当你在 React 组件中使用 Context API 并把状态或计算得来的值传递给 Provider 时,如果这些值没有被正确的缓存,每次组件重新渲染都会创建一个新的对象或函数。这会导致所有消费该 Context 的组件不必要地重新渲染,即使传递的值在逻辑上并没有变化。为了避免这种情况,你可以使用 useMemouseCallback 钩子来优化性能。

使用 useMemo 缓存复杂计算的值

javascript 复制代码
import React, { useContext, createContext, useState, useMemo } from 'react';

const MyContext = createContext();

function ChildComponent() {
  const contextValue = useContext(MyContext);
  console.log('ChildComponent rendered!');
  return <div>{contextValue.complexValue}</div>;
}

function ParentComponent() {
  const [count, setCount] = useState(0);
  
  // 使用 useMemo 来缓存复杂计算的结果
  const contextValue = useMemo(() => {
    const complexValue = doComplexCalculation(count);
    return { complexValue };
  }, [count]);

  return (
    <MyContext.Provider value={contextValue}>
      <ChildComponent />
      <button onClick={() => setCount(c => c + 1)}>Increment</button>
    </MyContext.Provider>
  );
}

function doComplexCalculation(value) {
  // 假设这是一个复杂的计算
  console.log('Doing complex calculation...');
  return value * 2; // 简单示例
}

export default ParentComponent;

在这个示例中,即使 ParentComponent 组件因状态更新而重新渲染,contextValue 只有在 count 状态改变时才会重新计算。这避免了 ChildComponentcontextValue 引用变化而不必要的重新渲染。

使用 useCallback 缓存函数

javascript 复制代码
import React, { useContext, createContext, useState, useCallback } from 'react';

const MyContext = createContext();

function ChildComponent() {
  const { increment } = useContext(MyContext);
  console.log('ChildComponent rendered!');
  return <button onClick={increment}>Increment</button>;
}

function ParentComponent() {
  const [count, setCount] = useState(0);
  
  // 使用 useCallback 来缓存回调函数
  const increment = useCallback(() => {
    setCount(c => c + 1);
  }, []);

  const contextValue = useMemo(() => {
    return { count, increment };
  }, [count, increment]);

  return (
    <MyContext.Provider value={contextValue}>
      <div>Count: {count}</div>
      <ChildComponent />
    </MyContext.Provider>
  );
}

export default ParentComponent;

在这个示例中,increment 函数被 useCallback 缓存了下来,它的引用在渲染之间保持不变。这确保了当 ParentComponent 重新渲染时,ChildComponent 不会因为 increment 函数的引用改变而重新渲染。

这两个例子展示了如何通过 useMemouseCallback 来避免不必要的渲染。在大型应用中,尤其是当你有很多消费 Context 的组件时,使用这些优化可以显著提高性能。不过,也应该注意不要过度优化,因为 useMemouseCallback 本身也有性能开销。只有在确实面临性能瓶颈时才考虑这些优化手段。

相关推荐
一次旅行5 分钟前
飞书接入龙虾后失联解决方法
前端·人工智能·chrome·飞书
晴天165 分钟前
【Electron】从零构建你的第一个桌面应用
前端·javascript·electron
斌味代码25 分钟前
Vue3源码解读(一):响应式系统 reactive/ref 核心原理图解(2026最新版)
前端·javascript·vue.js
yhole32 分钟前
Nginx解决前端跨域问题
运维·前端·nginx
我爱学习好爱好爱33 分钟前
Ansible 常用模块详解:hostname、selinux 、file实战
前端·chrome·ansible
爱丽_34 分钟前
AQS 的 `state`:volatile + CAS 如何撑起原子性与可见性
java·前端·算法
Zik----38 分钟前
Windows安装cuda
前端·ui·xhtml
王杨游戏养站系统38 分钟前
3分钟搭建1个游戏下载站网站教程!SEO站长养站系统!
开发语言·前端·游戏·游戏下载站养站系统·游戏养站系统
是上好佳佳佳呀39 分钟前
【前端(三)】CSS 属性梳理:从字体文本到背景表格
前端·css
gaolei_eit42 分钟前
Vue3信号(Signals)深度解析:重新思考响应式编程的未来
前端