PureComponent、React.memo详解
shouldComponentUpdate()
shouldComponentUpdate(nextProps, nextState) |
根据 shouldComponentUpdate()
的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。默认行为是 state 每次发生变化组件都会重新渲染。
当 props 或 state 发生变化时,shouldComponentUpdate()
会在渲染执行之前被调用。返回值默认为 true。首次渲染或使用 forceUpdate()
时不会调用该方法。
此方法仅作为**性能优化的方式**而存在。
- 如果是Class组件,应该考虑使用内置的
PureComponent
组件,而不是手动编写shouldComponentUpdate()
。PureComponent
会对 props 和 state 进行浅层比较,并减少了跳过必要更新的可能性。 - 如果是函数式组件,应该考虑使用内置的
React.memo
高阶函数对组件做一下包装。
注意:
不建议在
shouldComponentUpdate()
中进行深层比较或使用JSON.stringify()
。这样非常影响效率,且会损害性能。
在类组件更新函数updateClassInstance中
回调用checkShouldComponentUpdate函数,判断当前组件是否需要更新
- 如果componentshouldUpdate返回ture,就通过如下分支调用componentWillUpdate生命周期函数
- 如果componentshouldUpdate返回false
就需要把当前的props和state同上一次的props和state做比较。如果不同,还是会给当前节点打上更新的标签。
之后,我们再来看看checkShouldComponentUpdate到底做了什么。
从源码可以看到,checkShouldComponentUpdate先判断了类组件实例身上是否定义了shouldComponentUpdate方法。
- 如果有shouldComponentUpdate方法,就调用shouldComponentUpdate方法。
- 如果组件上,没有定义shouldComponentUpdate方法,那就返回true。
PureComponent
内置的 PureComponent
组件会对 props 和 state 进行浅层比较,来决定是否进行本轮更新。
可以从源码中看到,pureComponent
和Component
继承于同一父类,只是pureComponent
在它的原型对象上增加了一个isPureReactComponent
属性。
这个属性就是pureComponent
实现浅层比较的关键。
可以看到在checkShouldComponentUpdate
函数中,还有另一个条件判断,判断当前组件构造函数的原型对象上(也就是组件的原型对象)是否存在一个pureComponent
属性,就是判断这个组件是不是继承自pureComponent
,如果是,就会对组件的props和state做浅层比较。
shallowEqual函数
React.memo
const MyComponent = React.memo(function MyComponent(props) { |
React.memo
为高阶组件。它与 React.PureComponent
非常相似,但只适用于函数组件,而不适用 class 组件。
如果你的函数组件在给定相同 props 的情况下渲染相同的结果,那么你可以通过将其包装在 React.memo
中调用,以此通过记忆组件渲染结果的方式来提高组件的性能表现。这意味着在这种情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果。
React.memo
仅检查 props 变更。如果函数组件被 React.memo
包裹,且其实现中拥有 useState
或 useContext
的 Hook,当 context 发生变化时,它仍会重新渲染。
默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。
function MyComponent(props) { |
注意
与 class 组件中
shouldComponentUpdate()
方法不同的是,如果 props 相等,areEqual
会返回true
;如果 props 不相等,则返回false
。这与shouldComponentUpdate
方法的返回值相反。
源码
可以看到,memo返回了一个对象,这个对象在原组件之外增加一个属性compare
。
memo返回组件的具体更新逻辑在
react-reconciler -> ReactFiberBeginWork.old.js -> updateMemoComponent
在这个函数中,会取出compare
做判断,
- 如果有自定义的
compare
,就使用自定义的compare
。 - 如果没有自定义的
compare
,就和shouldComponentUpdate
一样,使用shallowEqual
函数。
参考:
React源码17.0.2