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中

image-20220704123900971

回调用checkShouldComponentUpdate函数,判断当前组件是否需要更新

image-20220704124038431

  • 如果componentshouldUpdate返回ture,就通过如下分支调用componentWillUpdate生命周期函数

image-20220704124245994

  • 如果componentshouldUpdate返回false

image-20220704124524160

就需要把当前的props和state同上一次的props和state做比较。如果不同,还是会给当前节点打上更新的标签。


之后,我们再来看看checkShouldComponentUpdate到底做了什么。

从源码可以看到,checkShouldComponentUpdate先判断了类组件实例身上是否定义了shouldComponentUpdate方法。

  • 如果有shouldComponentUpdate方法,就调用shouldComponentUpdate方法。

image-20220704124900240

  • 如果组件上,没有定义shouldComponentUpdate方法,那就返回true。

image-20220704125151227


PureComponent

内置的 PureComponent组件会对 props 和 state 进行浅层比较,来决定是否进行本轮更新。

可以从源码中看到,pureComponentComponent继承于同一父类,只是pureComponent在它的原型对象上增加了一个isPureReactComponent属性。

image-20220704125713211

这个属性就是pureComponent实现浅层比较的关键。

可以看到在checkShouldComponentUpdate函数中,还有另一个条件判断,判断当前组件构造函数的原型对象上(也就是组件的原型对象)是否存在一个pureComponent属性,就是判断这个组件是不是继承自pureComponent,如果是,就会对组件的props和state做浅层比较。

image-20220704130031449

shallowEqual函数

image-20220704131142807


React.memo

const MyComponent = React.memo(function MyComponent(props) {
/* 使用 props 渲染 */
});

React.memo高阶组件。它与 React.PureComponent 非常相似,但只适用于函数组件,而不适用 class 组件。

如果你的函数组件在给定相同 props 的情况下渲染相同的结果,那么你可以通过将其包装在 React.memo 中调用,以此通过记忆组件渲染结果的方式来提高组件的性能表现。这意味着在这种情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果。

React.memo 仅检查 props 变更。如果函数组件被 React.memo 包裹,且其实现中拥有 useStateuseContext 的 Hook,当 context 发生变化时,它仍会重新渲染。

默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。

function MyComponent(props) {
/* 使用 props 渲染 */
}
function areEqual(prevProps, nextProps) {
/*
如果把 nextProps 传入 render 方法的返回结果与
将 prevProps 传入 render 方法的返回结果一致则返回 true,
否则返回 false
*/
}
export default React.memo(MyComponent, areEqual);

注意

与 class 组件中 shouldComponentUpdate() 方法不同的是,如果 props 相等,areEqual 会返回 true;如果 props 不相等,则返回 false。这与 shouldComponentUpdate 方法的返回值相反。


源码

image-20220704134429681

可以看到,memo返回了一个对象,这个对象在原组件之外增加一个属性compare

memo返回组件的具体更新逻辑在

react-reconciler -> ReactFiberBeginWork.old.js -> updateMemoComponent

在这个函数中,会取出compare做判断,

  • 如果有自定义的compare,就使用自定义的compare
  • 如果没有自定义的compare,就和shouldComponentUpdate一样,使用shallowEqual函数。

image-20220704134936560


参考: