likes
comments
collection
share

memo 和 PureComponent 源码浅析

作者站长头像
站长
· 阅读数 10

PureComponent 和 memo 相信大家都用过,这里就不多介绍用法了,作用的话,在读源码以前,我通过八股文了解到是通过浅对比来减少 Render 的次数来达到优化性能的目的。那看了源码之后,发现其实通过八股文理解的其实不是很准确,真实情况是通过浅对比来判断是否复用组件对应的 fiber 结构,从而跳过组件在 Render 阶段的 diff (Reconcile)流程,而达到优化性能的目的。

PureComponent 实现原理

我们先来看下 Component 的实现: memo 和 PureComponent 源码浅析 再看看 PureComponent 的实现:

memo 和 PureComponent 源码浅析

可以看到,PureComponent 用 es5 的方式继承了 Component,因此可以说他俩完全一样,唯一的区别就是 PureComponent 多了个 isPureComponent 的属性。

既然他俩一样,那 PureComponent 怎么做的优化呢?继续跟着 PureComponent 的执行流程(和 Component 一致)走,发现关键就在 checkShouldComponentUpdate 方法里面,这里也是正常 Component 执行 shouldComponentUpdate 的地方。 memo 和 PureComponent 源码浅析 框里的代码就是 PureComponent 和 Component 不同的地方同时也是 PureComponent 做的优化,只有一行代码,返回了 props 和 state 浅比较(shallowEqual 浅比较的方法)的结果。当然这个优化是在没有定义 shouldComponentUpdate 生命周期的情况下才会生效,也可以理解为 PureComponent 帮我们实现了 shouldComponentUpdate。

memo 实现原理

既然类组件都有 PureComponent 的方式来帮助优化,那函数组件也不能少啊。React 提供了一个叫 memo 的 api 来达到和 PureComponent 一样的效果。接下来看看 memo 代码

memo 和 PureComponent 源码浅析

memo 接收两个参数,一个是 React组件,另一个是 compare 函数。返回一个新的 React 组件,类型为 memo,同时存储了自定义的比较函数 compare。

继续跟流程看源码,最终发现 memo Component在源码里分了两种类型,一种是 MemoComponent,另一种是 SimpleMemoComponent。后面再介绍两种的区别。

接下来看看是怎么优化更新的先看 SimpleMemoComponent:

memo 和 PureComponent 源码浅析 可以看到是浅比较了 Props。 下面看看 MemoComponent: 图中的 bailoutOnAlreadyFinishedWork 的方法就是复用老 fiber 节点的方法。

memo 和 PureComponent 源码浅析 可以看到调用了compare 方法,会根据 compare 的返回值来判断是否优化。需要注意的是 compare 和 shouldComponentUpdate 取值是相反的,compare是返回值为 true 不进行更新,而 shouldComponentUpdate 是返回 false 不进行更新。

SimpleMemoComponent 和 MemoComponent 的区别

  • MemoComponent 可以是函数组件也可以是类组件,SimpleMemoComponent 只能是函数组件
  • MemoComponent 会单独生成一个 Fiber 节点,memo 包裹的组件也会生成一个 Fiber 节点;SimpleMemoComponent 会和 memo 包裹的组件共用一个 Fiber节点;

那什么情况下是 SimpleMemoComponent 呢? memo 和 PureComponent 源码浅析 可以看到: 1、当传入的组件是函数组件且没有 defaultProps 2、compare 不存在 3、memo 也没有 defaultProps 满足上面三个条件就是 SimpleMemoComponent。

总结

管他什么SimpleMemo、Memo 的,类组件和函数组件都可以使用 memo 来优化就完事了。

优化的核心——浅对比怎么实现的

浅对比的方法就是 shallowEqual:

memo 和 PureComponent 源码浅析

为什么要用浅比较来进行优化呢?

因为 React 中的复用逻辑太难以达成了

memo 和 PureComponent 源码浅析 复用需要三个条件

  • Props 相同(=== 全等)
  • Context 没有改变
  • 自身 state 没有发生变化

最难达成的就是 Props 相等 ————— 比如在函数组件中你定义了个对象,并且传递给了子组件,那这个对象其实每次执行的时候都是一个新的对象,虽然他们的属性值一样。这就会造成没有意义的 reconcile,浪费性能。 因此就想到了通过 api 的形式来修改 Props 相同的判断条件,让其更容易成立,从而达到优化性能的目的。

最后

感谢大家的阅读,有不对的地方也欢迎大家指出来。

参考资料

React18.2.0源码