React.memo 实现原理解析

 更新时间:2025年09月09日 11:10:45   作者:维维酱  
React.memo通过props浅比较或自定义函数,结合Fiber优化机制,跳过组件渲染及副作用,下面就来详细的介绍一下,感兴趣的可以了解一下

核心实现概念

React.memo 的本质是一个高阶组件(HOC),它通过比较前后 props 来决定是否跳过组件的重新渲染。

1. 基本结构

在 React 源码中,React.memo 的实现大致如下:

function memo(type, compare) {
  // 创建一个特殊的元素类型
  const elementType = {
    $$typeof: REACT_MEMO_TYPE, // 特殊标识符,表示这是一个 memo 组件
    type, // 被包裹的原始组件
    compare: compare === undefined ? null : compare, // 自定义比较函数
  };
  
  return elementType;
}

2. 在协调(Reconciliation)过程中的处理

当 React 遇到 REACT_MEMO_TYPE 类型的元素时,会执行特殊处理:

// 简化版的协调逻辑
function updateMemoComponent(
  currentFiber, // 当前 Fiber 节点
  workInProgressFiber, // 工作中的 Fiber 节点
  Component, // 被 memo 包裹的组件
  nextProps, // 新的 props
  renderLanes // 渲染优先级
) {
  // 获取之前的 props
  const current = currentFiber.memoizedProps;
  
  // 决定使用哪种比较函数
  let compare = Component.compare;
  if (compare === null) {
    // 默认使用浅比较
    compare = shallowCompare;
  }
  
  // 检查 props 是否相等
  if (compare(current, nextProps)) {
    // Props 没有变化,完全跳过渲染
    // 复用之前的子节点
    return bailoutOnAlreadyFinishedWork(
      currentFiber,
      workInProgressFiber,
      renderLanes
    );
  }
  
  // Props 发生了变化,继续正常渲染流程
  return updateFunctionComponent(
    currentFiber,
    workInProgressFiber,
    Component,
    nextProps,
    renderLanes
  );
}

深入实现细节

1. 浅比较 (shallowCompare) 的实现

React 使用的默认浅比较函数类似于:

function shallowCompare(prevProps, nextProps) {
  // 如果 props 对象引用相同,直接返回 true
  if (prevProps === nextProps) {
    return true;
  }
  
  // 检查 props 键的数量
  const prevKeys = Object.keys(prevProps);
  const nextKeys = Object.keys(nextProps);
  
  if (prevKeys.length !== nextKeys.length) {
    return false;
  }
  
  // 逐个比较每个属性值
  for (let i = 0; i < prevKeys.length; i++) {
    const key = prevKeys[i];
    
    // 使用 Object.is 进行严格比较(类似于 ===,但处理了 NaN 和 +0/-0 的情况)
    if (!Object.is(prevProps[key], nextProps[key])) {
      return false;
    }
  }
  
  return true;
}

2. Fiber 架构中的优化机制

在 React 的 Fiber 架构中,React.memo 的优化是通过以下机制实现的:

  • 提前中止渲染:在 beginWork 阶段,如果检测到是 memo 组件且 props 未变化,React 会立即中止当前组件的渲染工作。
  • 子树复用:通过 bailoutOnAlreadyFinishedWork 函数,React 会标记整个子树为"无需更新",直接复用之前的渲染结果。
  • 跳过副作用:由于组件没有重新渲染,相关的副作用(如 useEffect)也不会被触发。

3. 与 React 渲染流程的整合

// 简化的渲染流程
function beginWork(currentFiber, workInProgressFiber, renderLanes) {
  // 检查是否是 memo 组件
  if (workInProgressFiber.type && workInProgressFiber.type.$$typeof === REACT_MEMO_TYPE) {
    return updateMemoComponent(
      currentFiber,
      workInProgressFiber,
      workInProgressFiber.type.type, // 提取原始组件
      workInProgressFiber.pendingProps,
      renderLanes
    );
  }
  
  // 处理其他类型的组件...
}

性能考虑与实现优化

1. 记忆化策略

React.memo 的实现采用了记忆化(Memoization)策略:

  • 存储之前的结果:React 会存储组件上一次的渲染结果(在 Fiber 节点的 memoizedStatememoizedProps 中)
  • 比较成本与渲染成本的权衡:浅比较的计算成本远低于组件的渲染成本(包括虚拟 DOM 创建和差异比较)

2. 选择性优化

React 不会对所有组件都应用 memo 优化,因为:

  • 比较本身有成本
  • 对于频繁更新或 props 经常变化的组件,memo 可能带来负收益

3. 与其他优化机制的协同

React.memo 与 React 的其他优化机制协同工作:

  • Context 优化:即使使用 React.memo,如果组件消费的 Context 值发生变化,组件仍会重新渲染
  • 状态更新优化:组件内部的状态更新不受 React.memo 影响

实际应用中的实现考虑

1. 自定义比较函数的高级用法

// 深度比较实现(不推荐在生产环境使用,仅作示例)
function deepCompare(prevProps, nextProps) {
  return JSON.stringify(prevProps) === JSON.stringify(nextProps);
}

// 选择性比较
function selectiveCompare(prevProps, nextProps) {
  // 只比较我们关心的属性
  return prevProps.importantValue === nextProps.importantValue;
}

const ExpensiveComponent = React.memo(
  function ExpensiveComponent(props) {
    // 组件实现
  },
  selectiveCompare // 使用自定义比较函数
);

2. 与 Hooks 的交互

React.memo 的实现需要考虑与 Hooks 的交互:

function MyComponent(props) {
  // 即使使用 React.memo,内部状态变化仍会导致重新渲染
  const [state, setState] = useState(0);
  
  // 使用 useMemo 和 useCallback 可以进一步优化
  const computedValue = useMemo(() => {
    return expensiveCalculation(props.someValue);
  }, [props.someValue]);
  
  const handleClick = useCallback(() => {
    // 处理点击
  }, []);
  
  return <div>{/* ... */}</div>;
}

export default React.memo(MyComponent);

总结

React.memo 的实现原理可以概括为:

  1. 高阶组件包装:通过创建特殊类型的 React 元素标记 memo 组件
  2. 协调阶段拦截:在协调过程中识别 memo 组件并执行特殊处理
  3. Props 比较:使用浅比较或自定义比较函数判断 props 是否变化
  4. 渲染优化:如果 props 未变化,跳过组件的渲染和子树的协调过程
  5. 结果复用:直接复用之前的渲染结果,避免不必要的计算和 DOM 操作

这种实现方式体现了 React 性能优化的核心思想:用较小的比较成本换取可能很大的渲染成本节约

到此这篇关于React.memo 实现原理解析的文章就介绍到这了,更多相关React.memo实现内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 浅析react里面如何封装一个通用的Ellipsis组件

    浅析react里面如何封装一个通用的Ellipsis组件

    这篇文章主要为大家详细介绍了在react里面如何封装一个通用的Ellipsis组件,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-12-12
  • 详解react-refetch的使用小例子

    详解react-refetch的使用小例子

    这篇文章主要介绍了详解react-refetch的使用小例子,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-02-02
  • react16+antd4 RangePicker组件实现时间禁选示例

    react16+antd4 RangePicker组件实现时间禁选示例

    这篇文章主要为大家介绍了react16+antd4 RangePicker 时间禁选示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • React前端开发createElement源码解读

    React前端开发createElement源码解读

    这篇文章主要为大家介绍了React前端开发createElement源码解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • 详解React Native 采用Fetch方式发送跨域POST请求

    详解React Native 采用Fetch方式发送跨域POST请求

    这篇文章主要介绍了详解React Native 采用Fetch方式发送跨域POST请求,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • 深入理解React 三大核心属性

    深入理解React 三大核心属性

    本文主要介绍了React 三大核心属性,主要包括State属性,Props属性,Refs属性,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • React Native提供自动完成的下拉菜单的方法示例

    React Native提供自动完成的下拉菜单的方法示例

    这篇文章主要为大家介绍了React Native提供自动完成的下拉菜单的方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • 使用react实现手机号的数据同步显示功能的示例代码

    使用react实现手机号的数据同步显示功能的示例代码

    本篇文章主要介绍了使用react实现手机号的数据同步显示功能的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • React优雅的封装SvgIcon组件示例

    React优雅的封装SvgIcon组件示例

    这篇文章主要为大家介绍了React优雅的封装SvgIcon组件示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • react中如何使用监听

    react中如何使用监听

    在 React 中,您可以使用 addEventListener 函数来监听事件,本文通过实例代码给大家介绍react中如何使用监听,感兴趣的朋友跟随小编一起看看吧
    2023-10-10

最新评论