# PureRender

## shouldComponentUpdate 作用

shouldComponentUpdate 是 PureRender 的关键之所在，这个生命周期钩子函数决定了需不需要执行 render 方法。一个组件的状态更新到真实 dom 的更新大致流程如下：

```
SCU(shouldComponentUpdate)  --true-->  render  --true-->  vDOMEq  --true--> realDOM
```

以 [React 官方的例子](https://doc.react-china.org/docs/optimizing-performance.html#shouldcomponentupdate%E5%BA%94%E7%94%A8) 为例，补充说明如下：

* `SCU`表明了`shouldComponentUpdate`的返回内容，绿色代表 true，会重新执行 render 方法；红色代表 false，不会执行 render 方法。
* `vDOMEq`表明了执行 v-diff 后待渲染的 v-dom 与原始 v-dom 是否相等，绿色代表相等，红色代表不等，需要更新 dom。
* 圆圈的颜色表明这个组件是否需要更新 dom，红色和 `vDOMEq` 的值的颜色一致。

![](https://1381653940-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LMDC17hlfiBPuoAp2bE%2F-LMDG-RUS1gaDmMWpRGw%2F-LMDG3n9aXlvZoro9MvT%2Fshould-component-update%20\(1\).png?generation=1536763913471642\&alt=media)

由于 C2 的`shouldComponentUpdate`返回了`false`，React 不会调用 C2 的 render 方法，也就不会生成 v-dom，甚至不会在 C4 和 C5 上调用`shouldComponentUpdate`。

对 C1 和 C3 来说，`shouldComponentUpdate`返回了`true`，因此 React 会深入到分支中并检查它们。C6 的`shouldComponentUpdate`返回了`true`，然后进行 v-diff，由于 `vDOMEq` 返回 false，React 会更新这个真实的 DOM 节点。

最后一个有趣的情况是 C8，`SCU` 为 true 会调用 render 方法进行 v-diff，但是由于`vDOMEq` 返回 true，因此它并没有更新这个真实的 DOM 节点。

分析完以上所有过程，我们会发现 React **只需更新 C6 的真实 DOM 节点**，因为它是不可避免的。对C8来说，它通过 v-diff 避免了更新真实 DOM，对 C2 的子树和 C7，它们甚至都没有执行比较，因为我们设置了`shouldComponentUpdate`为`false`，`render`没有被调用。

{% hint style="warning" %}
**注意**：虽然 C1 和 C3 节点被标记为红色，但实际更新真实 DOM 的时候只会更新 C6 节点。
{% endhint %}

## PureRender 本质

PureRender 的本质就是把 shouldComponentUpdate 函数用浅比较（shallowCompare）进行重写。

以下是 React 中 `shallowCompare.js` 的核心源码：

```javascript
function shallowCompare(instance, nextProps, nextState) {
  return !shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState);
}
```

�我们可以看到 shallowCompare 实际返回的是 shallowEqual 的**取反**结果，那 shallowEqual 的源码则是核心所在，react 的 shallowEqual 其实就是引用的 `fibjs` 库的 shallowEqual 方法。假设 objA，objB 都是对象，提取关键代码的核心思想进行了改写：

```javascript
function shallowEqual(objA, objB) {
  if (objA === objB) {
    return true;
  }

  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB);

  if (keysA.length !== keysB.length) {
    return false;
  }

  // 关键代码，只需关注 props 中每一个是否相等，无需深入判断
  return keysA.every(key => 
    Object.hasOwnProperty.call(objB, keys) &&
    objA[key] === objB[key];
  )
}
```

当 shallowEqual 为 true 的时候，shouldComponentUpdate 为 false，组件不会更新，这样便减少了某些组件的状态更新导致的一些不必要的 render 和 v-diff�。
