在上一章节,我们讲解了普通函数组件更新的基本流程,也知道了一个组件修改状态触发的更新,它的子组件也跟着重新渲染的原因。
所以本节就将从React.memo方法来解析函数组件的性能优化处理。
1,案例准备
这是之前的测试案例:
js
// MyFun.js
import { useState } from 'react'
import Child from './Child'
export default function MyFun(props) {
console.log('MyFun组件运行了')
const [count, setCount] = useState(1)
function handleClick() {
setCount(count + 1)
}
return (
<div className='MyFun'>
<div>state: {count}</div>
<Child name='Child'></Child>
<button onClick={handleClick}>更新</button>
</div>
)
}
js
// Child.js
export default function Child(props) {
console.log('Child组件运行了')
return (
<div className='Child'>
<div>Child子组件</div>
<div>name: {props.name}</div>
</div>
)
}
每当我们点击MyFun组件中的更新按钮时,Child子组件都会重新渲染一次:

我们点击了三次更新按钮,Child子组件也跟着父组件重新渲染了三次,这就是普通的函数组件更新。
React.memo方法
React.memo方法的作用:创建函数组件中的纯组件,在 props 没有发生变化的情况下跳过重新渲染re-render。
此方法常用于普通函数组件或者
forwardRef组件。
下面我们使用React.memo方法来优化child组件。
js
// MyFun.js
import { useState } from 'react'
import NewChild from './NewChild'
export default function MyFun(props) {
console.log('MyFun组件运行了')
const [count, setCount] = useState(1)
function handleClick() {
setCount(count + 1)
}
return (
<div className='MyFun'>
<div>state: {count}</div>
<NewChild name='NewChild'></NewChild>
<button onClick={handleClick}>更新</button>
</div>
)
}
js
// Child.js
import React from 'react'
function Child(props) {
console.log('Child组件运行了')
return (
<div className='Child'>
<div>Child子组件</div>
<div>name: {props.name}</div>
</div>
)
}
const NewChild = React.memo(Child)
export default NewChild
这时我们再点击MyFun组件中的更新按钮时,Child子组件就不会再跟着重新渲染了:

方法原理
首先查看memo方法源码:
js
// react/src/ReactMemo.js
export function memo<Props>(
type: React$ElementType,
compare?: (oldProps: Props, newProps: Props) => boolean,
) {
// 定义一个新的组件,包装传入的函数组件
const elementType = {
// 存储组件类型 memo
$$typeof: REACT_MEMO_TYPE,
type,
# 一个cb回调函数,用于自定义校验props,根据校验结果决定是否需要重新渲染
compare: compare === undefined ? null : compare,
};
// 返回包装后的组件
return elementType;
}
从上面的源码可以看出,memo方法的内容比较简单,而且和forwardRef方法原理基本一致。它的方法内容就是定义一个新的内部组件,包装传入的函数组件,即将我们传递的函数组件存储到type属性上,然后返回包装后的组件即memo组件。
下面我们就开始解析React.memo方法创建的memo组件在加载和更新时具体的执行逻辑。
2,加载流程
首先查看memo组件的加载流程,因为memo组件首次加载会做一些比较重要的处理,我们需要了解。
开始执行memo组件对应Fiber节点的beginWork工作:
js
// react-reconciler/src/ReactFiberBeginWork.new.js
function beginWork() {
...
// 根据fiber.tag,进入不同组件处理逻辑
switch (workInProgress.tag) {
case FunctionComponent: {}
case ClassComponent: {}
case HostRoot: {}
case HostComponent: {}
...
// 普通memo组件处理 14
case MemoComponent: {
const type = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
let resolvedProps = resolveDefaultProps(type, unresolvedProps);
// 进入加载流程
return updateMemoComponent()
}
// simpleMemo组件处理 15
case SimpleMemoComponent: {
return updateSimpleMemoComponent()
}
}
}
首次加载时,该Fiber节点的tag属性值为14,直接进入MemoComponent分支处理逻辑:

js
case MemoComponent: {
// 组件type原型
const type = workInProgress.type;
// 等待处理的props
const unresolvedProps = workInProgress.pendingProps;
// 处理props默认值,两次
let resolvedProps = resolveDefaultProps(type, unresolvedProps);
resolvedProps = resolveDefaultProps(type.type, resolvedProps);
return updateMemoComponent(
current,
workInProgress,
type, // memo组件对象
resolvedProps,
renderLanes,
);
}
这里取出Fiber节点的type属性内容,也就是memo组件对象的内容:

然后就是设置props的默认值:
js
let resolvedProps = resolveDefaultProps(type, unresolvedProps);
resolvedProps = resolveDefaultProps(type.type, resolvedProps);
这里做了两次默认值处理:
- 第一次是对
memo组件的处理。 - 第二次是对包裹的
Child组件默认值处理。
最后调用一个updateMemoComponent方法,开始memo组件的加载处理。
updateMemoComponent
查看updateMemoComponent方法:
js
// react-reconciler/src/ReactFiberBeginWork.new.js
function updateMemoComponent(
current: Fiber | null,
workInProgress: Fiber,
Component: any, // Fiber.type
nextProps: any,
renderLanes: Lanes,
): null | Fiber {
# 加载阶段
if (current === null) {
const type = Component.type;
if (
isSimpleFunctionComponent(type) &&
Component.compare === null &&
Component.defaultProps === undefined
) {
let resolvedType = type;
// 1,SimpleMemo组件加载
// 【重点】设置为SimpleMemo组件的tag,更新时就会走updateSimpleMemoComponent分支
workInProgress.tag = SimpleMemoComponent;
workInProgress.type = resolvedType;
return updateSimpleMemoComponent(
current,
workInProgress,
resolvedType,
nextProps,
renderLanes,
);
}
// 2,普通memo组件加载,直接创建子节点
const child = createFiberFromTypeAndProps(
Component.type,
null,
nextProps,
workInProgress,
workInProgress.mode,
renderLanes,
);
child.ref = workInProgress.ref;
child.return = workInProgress;
workInProgress.child = child;
return child;
}
# 更新阶段
const currentChild = ((current.child: any): Fiber); // This is always exactly one child
const hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(
current,
renderLanes,
);
if (!hasScheduledUpdateOrContext) {
// This will be the props with resolved defaultProps,
// unlike current.memoizedProps which will be the unresolved ones.
const prevProps = currentChild.memoizedProps;
// Default to shallow comparison
let compare = Component.compare;
compare = compare !== null ? compare : shallowEqual;
if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {
// 跳过更新,返回原来的节点
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
}
// React DevTools reads this flag.
// 创建新的节点
workInProgress.flags |= PerformedWork;
const newChild = createWorkInProgress(currentChild, nextProps);
newChild.ref = workInProgress.ref;
newChild.return = workInProgress;
workInProgress.child = newChild;
return newChild;
}
首先通过判断current节点是否为null来区分加载阶段和更新阶段。当前为加载阶段current为null,继续查看memo组件加载阶段的逻辑处理。
js
const type = Component.type;
注意: 这里的Component是memo组件对象,可以查看上面的调试截图,取出的type才是Child组件本身。 在取出Child组件函数后,又通过一个条件判断,将memo组件的加载分成了两个分支逻辑:
simpleMemo组件加载。- 普通
memo组件加载。
js
if (isSimpleFunctionComponent(type) && Component.compare === null && Component.defaultProps === undefined) {
// 1,simpleMemo组件加载
}
// 2,普通memo组件加载
同时满足上面三个判断条件的就是simpleMemo组件。
首先看第一个判断条件isSimpleFunctionComponent(type):是否为简单函数组件。
js
// 判断是否为普通函数组件 forwardRef组件是对象:{$$typeof: Symbol(react.forward_ref)}
export function isSimpleFunctionComponent(type: any) {
return (
typeof type === 'function' && // 排除forwardRef组件
!shouldConstruct(type) && // 排除类组件
type.defaultProps === undefined // 无defaultProps
);
}
注意: 这个方法的作用其实就是判断我们优化的这个组件:是否为简单函数组件:
- 第一个条件是排除
forwardRef组件【对象】,因为memo组件也可以接收forwardRef组件。 - 第二个条件是排除类组件,不能存在构造器。
- 第三个条件是不存在
defaultProps。
只有同时满足这三个条件,才表示是简单函数组件simpleFunctionComponent。
再看simpleMemo组件剩下的判断条件:即memo组件没有compare比较函数且自身也不存在defaultProps。同时满足这三个条件即可以认定为simpleMemo组件。
组件区分
到这里我们来进行一个总结,以此区分simpleMemo组件和普通memo组件:
simpleMemo组件:
React.memo(Com, null)方法组件参数为简单函数组件,且memo组件自身无compare参数,无defaultProps。
memo组件:不满足simpleMemo组件条件的就是普通memo组件,比如:
React.memo(Com, compare)方法组件参数为简单函数组件,但memo组件自身存在compare参数或者defaultProps。React.memo(Com, compare)方法组件参数为forwardRef组件,此时不管存不存在compare参数或者defaultProps,它都是普通memo组件。
memo组件加载
如果是普通memo组件:就是继续创建子节点内容,最后返回子节点。
js
// 普通memo组件加载
const child = createFiberFromTypeAndProps(
Component.type,
null,
nextProps,
workInProgress,
workInProgress.mode,
renderLanes,
);
child.ref = workInProgress.ref;
child.return = workInProgress;
workInProgress.child = child;
// Child组件 Fiber节点
return child;
通过普通memo组件的加载可以得知一个结论:普通memo组件会为包装的组件创建独立的的Fiber节点。
simpleMemo组件加载
这里我们的重点是查看simpleMemo组件的处理,因为当前我们传入的child满足simpleMemo组件的所有条件:
js
if (isSimpleFunctionComponent(type) && Component.compare === null && Component.defaultProps === undefined) {
# simpleMemo组件加载
let resolvedType = type;
// 【重点】设置为简单memo组件的tag,更新时就会走updateSimpleMemoComponent分支
workInProgress.tag = SimpleMemoComponent;
workInProgress.type = resolvedType;
// 简单函数组件,没有defaultProps
return updateSimpleMemoComponent(
current,
workInProgress,
resolvedType,
nextProps,
renderLanes,
);
}
注意: 在判定为simpleMemo组件之后,将当前Fiber节点的tag属性设置为了SimpleMemoComponent对应的值,作用是此节点在更新阶段就可以直接进入updateSimpleMemoComponent分支逻辑处理,并且这里重置了Fiber节点的type属性,原来是memo组件对象,现在变成了Child组件函数【这样simpleMemo组件在加载阶段就和普通函数组件一致了】,查看调试截图印证:

最后调用updateSimpleMemoComponent方法,开始simpleMemo组件的加载。
updateSimpleMemoComponent
查看updateSimpleMemoComponent方法:
js
// react-reconciler/src/ReactFiberBeginWork.new.js
function updateSimpleMemoComponent(
current: Fiber | null,
workInProgress: Fiber,
Component: any,
nextProps: any,
renderLanes: Lanes,
): null | Fiber {
# 更新阶段
if (current !== null) {
const prevProps = current.memoizedProps;
// 普通函数组件基本满足,props无变化,ref为null
if (
shallowEqual(prevProps, nextProps) &&
current.ref === workInProgress.ref &&
// Prevent bailout if the implementation changed due to hot reload.
(__DEV__ ? workInProgress.type === current.type : true)
) {
didReceiveUpdate = false;
workInProgress.pendingProps = nextProps = prevProps;
if (!checkScheduledUpdateOrContext(current, renderLanes)) {
workInProgress.lanes = current.lanes;
// 复用原来的节点,跳过更新
return bailoutOnAlreadyFinishedWork(
current,
workInProgress,
renderLanes,
);
} else if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {
didReceiveUpdate = true;
}
}
}
# 加载阶段:其实就是普通函数组件加载逻辑
// 更新阶段:不满足上面的优化条件时,也会进入普通函数组件的更新流程
return updateFunctionComponent(
current,
workInProgress,
Component,
nextProps,
renderLanes,
);
}
此方法中同样是通过判断current节点是否有值来区分加载阶段和更新,当前为加载阶段最后直接调用了一个updateFunctionComponent方法,也就是说simpleMemo组件的加载逻辑实际上调用的普通函数组件的加载逻辑。
3,更新流程
触发更新
点击MyFun组件的更新按钮,触发一次更新流程。

下面我们直接快进来到MyFun组件的更新逻辑:

MyFun组件在调用renderWithHooks方法之后,会根据组件返回的jsx内容重新创建所有子节点对应的react元素对象。
其中就包含了memo组件对应的react元素对象:

这里react元素对象的type属性存储的就是上面memo方法里面的elementType对象,而它内部的type属性才是原始的child组件。
下面我们继续快进,直接来到memo组件的更新流程,开始执行memo组件对应Fiber节点的beginWork工作:
js
// react-reconciler/src/ReactFiberBeginWork.new.js
function beginWork() {
if (current !== null) {
// 更新逻辑
const oldProps = current.memoizedProps;
const newProps = workInProgress.pendingProps;
// 主要判断:props变化和context上下文变化
if (oldProps !== newProps || hasLegacyContextChanged() ) {
// props有变化或者上下文有变化时,Fiber节点自身需要更新就会进入这里
didReceiveUpdate = true;
} else {
// 无变化,进入Bailout策略
...
}
} else {
// 加载逻辑
didReceiveUpdate = false;
}
...
// 根据fiber.tag,进入不同组件处理逻辑
switch (workInProgress.tag) {
case FunctionComponent: {}
case ClassComponent: {}
case HostRoot: {}
case HostComponent: {}
...
// 普通memo组件处理 14
case MemoComponent: {
const type = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
let resolvedProps = resolveDefaultProps(type, unresolvedProps);
// 进入加载流程
return updateMemoComponent()
}
// simpleMemo组件处理 15
case SimpleMemoComponent: {
return updateSimpleMemoComponent()
}
}
}
这里memo组件节点的pendingProps属性接收的新建的react元素对象传递的props数据,所以这里的新旧props不相等,不满足Bailout优化策略,会执行正常的更新流程。
simpleMemo组件更新
当前我们为simpleMemo组件,它的tag为15【前面加载阶段中更新的tag属性】,所以这里更新时会直接进入SimpleMemoComponent分支逻辑,下面我们继续查看它的更新逻辑。

直接进入updateSimpleMemoComponent方法的更新逻辑:
js
// react-reconciler/src/ReactFiberBeginWork.new.js
function updateSimpleMemoComponent(
current: Fiber | null,
workInProgress: Fiber,
Component: any,
nextProps: any,
renderLanes: Lanes,
): null | Fiber {
# 更新阶段
if (current !== null) {
const prevProps = current.memoizedProps;
// 普通函数组件基本满足,props无变化,ref为null
if (shallowEqual(prevProps, nextProps) && current.ref === workInProgress.ref) {
didReceiveUpdate = false;
workInProgress.pendingProps = nextProps = prevProps;
if (!checkScheduledUpdateOrContext(current, renderLanes)) {
workInProgress.lanes = current.lanes;
// 复用原来的节点,跳过更新
return bailoutOnAlreadyFinishedWork(
current,
workInProgress,
renderLanes,
);
}
}
}
// 加载阶段
// 或者不满足优化策略条件时,进入普通函数组件更新流程
return updateFunctionComponent(current, workInProgress, Component, nextProps, renderLanes)
}
注意: 这里判断current时和下面的updateFunctionComponent并不是if else,即不是二选一的逻辑。在当前更新流程中,如果不满足Bailout优化策略条件,则还是会进入下面的updateFunctionComponent方法,执行普通函数组件的更新流程。
所以
memo方法优化函数组件的原理就是:在函数组件更新之前,再执行一次Bailout策略校验。
我们继续查看simpleMemo组件的优化逻辑,首先从current节点上取出旧的props对象:
js
const prevProps = current.memoizedProps;
然后调用默认的shallowEqual方法对新旧props对象进行浅比较,判断props是否发生了变化:
js
if (shallowEqual(prevProps, nextProps) && current.ref === workInProgress.ref)
这里我们接着查看shallowEqual浅比较方法:
shallowEqual
js
// packages\shared\shallowEqual.js
import is from './objectIs';
import hasOwnProperty from './hasOwnProperty';
// 浅比较
export default function shallowEqual(objA: mixed, objB: mixed): boolean {
// objA:旧的props; objB:新的props
if (is(objA, objB)) {
return true;
}
if (
typeof objA !== 'object' ||
objA === null ||
typeof objB !== 'object' ||
objB === null
) {
return false;
}
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);
if (keysA.length !== keysB.length) {
return false;
}
// Test for A's keys different from B.
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;
}
一进入shallowEqual方法,首先就使用Object.is()来判断新旧props对象是否相等:

注意: 实际情况中组件更新时,新旧props对象都不会相等,以当前案例中的MyFun组件为例,每次当该组件更新时,它都会重新创建组件内所有的子节点的react元素对象【其中就包括newChild组件】,在创建react元素对象时,每次都是新建的一个props对象,所以即使你的props没有任何数据为空对象,它也不会和旧的props对象相等。
yaml
{} !== {}
而Child组件Fiber节点的props对象就是取自于它对应的react元素对象,所以这里第一个判断条件无法满足。
shallowEqual方法剩下判断逻辑就比较简单了:通过Object.keys方法得到新旧props对象的keys,然后循环旧props对象的keys,判断新props对象是否存在对应的属性以及属性值是否相等:
- 如果有任何一个属性判断不通过,则返回
false,表示props发生变化,需要执行普通函数组件的更新流程。 - 如果所有判断条件都通过,则返回
true,表示props没有发生变化,可以执行进一步的优化策略。
js
if (shallowEqual(prevProps, nextProps) && current.ref === workInProgress.ref)
最后还要注意:这里除了判断props之外,还判断了ref对象的变化。
这也就是为何函数组件要使用useRef来创建ref对象的原因,以此固定ref对象的引用地址,这样我们在使用React.memo方法优化函数组件时,才能够满足这个判断条件,以此进入Bailout优化策略。
当前我们的simpleMemo组件满足判断条件:props对象无属性变化,没有使用ref,所以ref对象都为null。
然后设置全局变量didReceiveUpdate为false,表示不需要更新。
ini
didReceiveUpdate = false;
在通过上面的判断条件通过后,还需要继续判断是否存在更新。在第一章节已经讲述过,影响Fiber节点更新有三个因素:props,state和context,当前仅仅是通过了props的判断,还需要执行进一步的优化条件判断:
js
// 进一步的优化条件判断
if (!checkScheduledUpdateOrContext(current, renderLanes)) {
workInProgress.lanes = current.lanes;
// 优化策略工作
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
调用checkScheduledUpdateOrContext方法来判断state和context变化影响的更新,这里的判断逻辑和前面的beginWork中的判断逻辑完全一致,因为它们本来就是相同的Bailout策略校验,两个不同的地方触发的校验,唯一的区别就是对props的校验有所不同,所以这里就直接快速说明了,详细的逻辑可以查看《React函数组件性能优化三部曲(一)》。
检查当前Fiber节点是否存在等待处理的更新:
- 如果存在:则返回
true,取反后为false,不满足Bailout策略,进入普通的函数组件更新流程。 - 如果不存在:则返回
false,取反后为true,满足Bailout策略,进入组件优化策略流程。
当上面的校验都通过后,进入bailoutOnAlreadyFinishedWork方法,执行进一步的优化程度判断。
bailoutOnAlreadyFinishedWork
查看bailoutOnAlreadyFinishedWork方法:
js
// packages\react-reconciler\src\ReactFiberBeginWork.new.js
function bailoutOnAlreadyFinishedWork(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
): Fiber | null {
if (current !== null) {
workInProgress.dependencies = current.dependencies;
}
// 标记跳过更新的lanes
markSkippedUpdateLanes(workInProgress.lanes);
// 检查当前节点的子树是否存在更新的工作
if (!includesSomeLane(renderLanes, workInProgress.childLanes)) {
return null;
}
// 当前Fiber节点没有更新工作,但是它的子树有更新工作,克隆下一层子节点,继续执行子节点的beginWork工作
cloneChildFibers(current, workInProgress);
return workInProgress.child;
}
这个方法是Bailout优化策略的核心方法,它的作用执行进一步的优化程度判断:
- 高度优化:跳过整个子树的更新流程。
- 一般优化:跳过自身节点的更新流程。
当前我们的simpleMemo组件【Child】满足高度优化策略,就会直接跳过该组件所有节点的更新流程。
这就是React.memo方法对函数组件的优化作用,它的实际原理就是在beginWork之后,组件更新之前,再执行一次Bailout策略校验。
到此simpleMemo组件的更新逻辑就执行完成。
memo组件更新
下面我们再来查看一下普通memo组件的更新流程,此时我们需要对之前案例进行改造,最简单的就是传递forwardRef组件。
js
// MyFun.js
import { useState, useRef } from 'react'
import NewChild from './NewChild'
export default function MyFun(props) {
console.log('MyFun组件运行了')
const [count, setCount] = useState(1)
const ref = useRef()
function handleClick() {
setCount(count + 1)
}
return (
<div className='MyFun'>
<div>state: {count}</div>
<NewChild name='NewChild' ref={ref}></NewChild>
<button onClick={handleClick}>更新</button>
</div>
)
}
js
// NewChild.js
import React from 'react'
function Child(props, ref) {
console.log('Child组件运行了')
return (
<div className='Child'>
<div ref={ref}>Child子组件</div>
<div>name: {props.name}</div>
</div>
)
}
const NewChild = React.memo(React.forwardRef(Child))
export default NewChild
下面我们直接来到它的更新流程:
js
// react-reconciler/src/ReactFiberBeginWork.new.js
function updateMemoComponent(
current: Fiber | null,
workInProgress: Fiber,
Component: any,
nextProps: any,
renderLanes: Lanes,
): null | Fiber {
# 加载阶段
if (current === null) {
...
}
# 更新阶段
const currentChild = current.child; // This is always exactly one child
const hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(
current,
renderLanes,
);
if (!hasScheduledUpdateOrContext) {
const prevProps = currentChild.memoizedProps;
// Default to shallow comparison
let compare = Component.compare;
compare = compare !== null ? compare : shallowEqual;
if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {
// 跳过更新,返回原来的节点
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
}
// 不满足bailout策略时
// 根据旧的节点内容及新的props创建新的Fiber节点
const newChild = createWorkInProgress(currentChild, nextProps);
newChild.ref = workInProgress.ref;
newChild.return = workInProgress;
workInProgress.child = newChild;
return newChild;
}
这里我们可以看出普通memo组件和simpleMemo组件更新时是基本一致的,也是执行一次Bailout策略校验:
- 校验通过,则进入
Bailout策略逻辑。 - 校验不通过,则直接复用旧节点信息以及新的
props生成新的Fiber节点,然后执行组件正常的更新逻辑。
这里和simpleMemo组件更新不同的地方在于,如果传递了自定义compare比较函数,则调用此方法,如果没有传递这个参数,则会使用默认的shallowEqual方法进行props的浅比较。
4,总结
1,当我们使用React.memo(Com, null)方法来优化我们的函数组件时,会根据传递的参数不同,在react内部划分为两种组件类型:
simpleMemo组件- 普通
memo组件
2,这两个组件具体的区分条件为:
simpleMemo组件:
React.memo(Com, null)方法组件参数为简单函数组件,且memo组件自身无compare参数,无defaultProps。
simpleFunctionComponent简单函数组件条件:必须为函数组件且自身无defaultProps。
memo组件:不满足simpleMemo组件条件的就是普通memo组件,比如:
React.memo(Com, compare)方法组件参数为简单函数组件,但memo组件自身存在compare参数或者defaultProps。React.memo(Com, compare)方法组件参数为forwardRef组件,此时不管存不存在compare参数或者defaultProps,它都是普通memo组件。
3,这两个组件在更新阶段主要的区别就是对props校验的不同:
simpleMemo组件使用react内部默认的shallowEqual浅比较方法。- 普通
memo组件可以使用用户传递的自定义的compare比较函数,如果没有传递则也是使用默认的shallowEqual方法。
当然这两个组件在不满足Bailout策略时,创建子节点的逻辑也些许不同,不过这个对我们来说不是重点。
4,simpleMemo组件和普通memo组件可以统称为memo组件:因为它们优化函数组件的原理是相同的,就是在该节点beginWork之后,函数组件更新之前,再执行一次Bailout策略校验,其实就是多给函数组件一次救赎的机会。
结束语
以上就是React.memo方法优化函数组件的全部内容了,觉得有用的可以点赞收藏!如果有问题或建议,欢迎留言讨论!