Jinuss's blog Jinuss's blog
首页
  • 源码合集

    • Leaflet源码分析
    • Openlayers源码合集
    • vue3源码
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

Web、WebGIS技术博客
首页
  • 源码合集

    • Leaflet源码分析
    • Openlayers源码合集
    • vue3源码
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 《React源码》笔记
  • React-reconciler
东流
2026-04-01
目录

memo组件

# 概述

React.memo用于缓存组件,可以避免组件不必要的更新。React.memo可以缓存函数组件和class类组件。

# 源码分析

同React.forwardRef类似,React.memo本质上也是包装下组件,打上$$typeof标记,返回一个对象。

function memo(type,compare){
    return {
        $$typeof:Symbol.for('react.memo')
        type,
        compare:compare === undefined ? null : compare
    }
}
1
2
3
4
5
6
7

在生成fiber时,被React.memo包装的组件对应生成的fiber.tag是MemoComponent(14)

# updateMemoComponent

在beginWork阶段,React.memo会调用updateMemoComponent来处理子节点fiber。

function updateMemoComponent(
  current,
  workInProgress,
  Component,
  nextProps,
  renderLanes,
) {
  // 首次渲染,挂载时
  if (current === null) {
    // 获取memo包裹的组件
    const type = Component.type;
    // 若包裹的组件是一个函数组件并且没有传递比较函数compare
    if (isSimpleFunctionComponent(type) && Component.compare === null) {
      let resolvedType = type;
      // 修改fiber的tag和type
      workInProgress.tag = SimpleMemoComponent;
      workInProgress.type = resolvedType;
      // 调用updateSimpleMemoComponent方法,并返回
      return updateSimpleMemoComponent(
        current,
        workInProgress,
        resolvedType,
        nextProps,
        renderLanes,
      );
    }
    // 若包裹的组件不是一个函数组件或者compare不为null,则调用createFiberFromTypeAndProps重新生成一个fiber作为子节点
    const child = createFiberFromTypeAndProps(
      Component.type,
      null,
      nextProps,
      workInProgress,
      workInProgress.mode,
      renderLanes,
    );
    // 将当前fiber的ref赋值给子节点
    child.ref = workInProgress.ref;
    // 维护父子fiber指向
    child.return = workInProgress;
    workInProgress.child = child;
    // 返回子fiber
    return child;
  }
  
  // 若是更新阶段
  
  // 取旧fiber上的子节点
  const currentChild = current.child; 
  
  // 判断是否需要安排更新:调用checkScheduledUpdateOrcontext检测
  const hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(
    current,
    renderLanes,
  );
  // 若不需要更新,
  if (!hasScheduledUpdateOrContext) {
    // 从旧fiber上取出旧属性
    const prevProps = currentChild.memoizedProps;
    
    // 判断是否传了检测函数,若没传,则采用shallowEqual进行浅比较
    let compare = Component.compare;
    compare = compare !== null ? compare : shallowEqual;
    // 比较新旧属性是否发生改变以及新旧fiber的ref是否发生了改变
    if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {
      // 若满足条件,则调用bailoutOnAlreadyFinishedWork进入bailout优化机制
      return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
    }
  }
  
  // 若需要更新,则调用createWorkInProgress创建子fiber
  const newChild = createWorkInProgress(currentChild, nextProps);
  // 传递ref
  newChild.ref = workInProgress.ref;
  // 保证指向
  newChild.return = workInProgress;
  workInProgress.child = newChild;
  // 最后返回子fiber
  return newChild;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

# updateSimpleMemoComponent

若React.memo包装的是一个函数组件,且没有自定义compare方法,则React会将当做一个SimpleMemoComponent类型的fiber来处理,调用updateSimpleMemoComponent方法处理子节点,即包裹的函数组件。

function updateSimpleMemoComponent(
  current,
  workInProgress,
  Component,
  nextProps,
  renderLanes,
) {
  // 判断旧fiber是否存在,
  if (current !== null) {
  // 若存在,则说明是更新操作
    // 获取旧fiber上的旧属性
    const prevProps = current.memoizedProps;
    // 调用shallowEqual方法判断属性是否发生变化,若未变化,且ref没变
    if (
      shallowEqual(prevProps, nextProps) &&
      current.ref === workInProgress.ref
    ) {
      // 则将didReceiveUpdate置为false,表示要短路更新
      didReceiveUpdate = false;
      // 将旧属性赋值给新属性以及fiber上的属性
      workInProgress.pendingProps = nextProps = prevProps;
      // 调用checkScheduledUpdateOrContext检测子组件是否有更新以及context是否有变化,若未变化,则进入bailout优化
      if (!checkScheduledUpdateOrContext(current, renderLanes)) {
        workInProgress.lanes = current.lanes;
        return bailoutOnAlreadyFinishedWork(
          current,
          workInProgress,
          renderLanes,
        );
      } else if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {
      // 若上述条件不满足,且flags上有强制更新,则将didReceiveUpdate置为true
        didReceiveUpdate = true;
      }
    }
  }

  // 旧Fiber不存在,说明是挂载操作,首次渲染直接调用updateFunctionComponent方法,并返回其结果 
  return updateFunctionComponent(
    current,
    workInProgress,
    Component,
    nextProps,
    renderLanes,
  );
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# 辅助方法

# shallowEqual

shallowEqual方法用于浅比较两个对象是否相等。is即Object.is,是 JavaScript 中用于判断两个值是否严格相等的方法。

function shallowEqual(objA, objB) {
  // 首先判断objA与objB是否严格相等,
  if (is(objA, objB)) {
    return true;
  }
  
  // 检测objA,objB的类型
  if (
    typeof objA !== 'object' ||
    objA === null ||
    typeof objB !== 'object' ||
    objB === null
  ) {
    return false;
  }
  
  // 获取objA,objB的key值数组
  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB);
  
  // 若key的长度不相等,则返回false
  if (keysA.length !== keysB.length) {
    return false;
  }
  
  // 比较objA和objB的属性值是否相等
  for (let i = 0; i < keysA.length; i++) {
    const currentKey = keysA[i];
    if (
      !hasOwnProperty.call(objB, currentKey) ||
      !is(objA[currentKey], objB[currentKey])
    ) {
      return false;
    }
  }

  return true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
编辑 (opens new window)
上次更新: 2026/04/03, 01:41:21
最近更新
01
useId
04-03
02
useImperativeHandle
04-01
03
forwardRef组件
04-01
更多文章>
Theme by Vdoing | Copyright © 2024-2026 东流 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式