如何使用 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 本身也有性能开销。只有在确实面临性能瓶颈时才考虑这些优化手段。

相关推荐
angushine21 小时前
Python常用方法
开发语言·前端·python
C澒21 小时前
AI 生码 - D2C:Figma to Code 全流程实现
前端·低代码·ai编程·figma
敲代码的鱼哇21 小时前
发送短信/拨打电话/获取联系人能力 UTS 插件(cz-sms)
android·前端·ios·uni-app·安卓·harmonyos·鸿蒙
搬搬砖得了1 天前
Vue 响应式对象异步赋值作为 Props:二次渲染问题与组件设计哲学
前端·vue.js
张西餐1 天前
Promise的理解
前端
天渺工作室1 天前
别再写改名脚本了,一个 Vite 插件搞定压缩、校验、自动哈希命名vite-plugin-pack-orchestrator
前端·vite
大龄程序员狗哥1 天前
第30篇:使用Flask部署你的第一个AI模型——打造简易Web API(项目实战)
前端·人工智能·flask
AI砖家1 天前
解剖 Claude Code:如何搭建一个企业级的私有化 AI 编程助手
前端·人工智能·ai编程
用户5757303346241 天前
拒绝“首屏爆炸”:用 React 哨兵模式与懒加载打造丝滑列表
前端
大腕先生1 天前
通用分页超详细介绍(附带源代码解析&页面展示效果)
xml·java·linux·服务器·开发语言·前端·idea