ReactJS - Reconciliation
Reconciliation 是 React 库的一个内部过程。我们知道,React 应用程序会创建一个虚拟 DOM,然后根据虚拟 DOM 更新应用程序的实际 DOM。每当 React 收到更新请求时,它都会首先创建一个虚拟 DOM,然后使用不同的差异算法将虚拟 DOM 与之前的状态进行比较,然后只有在绝对必要时才会更新 DOM。
尽管差异算法和更新 DOM 是 React 核心内部的,但了解一些内部内容将有助于我们调整应用程序以最大限度地利用 React 库。
差异算法
让我们在本章中看看 React 核心应用的一些差异算法。
相同类型的元素
每当 React 组件将元素从一种类型更改为另一种类型(例如从 div 更改为更具体的 p)时,整个 React 虚拟 DOM 树都会发生变化并触发 DOM 更新。
<!-- Before --> <div> <Content /> </div> <!-- After --> <p> <Content /> </p>
此时,整个元素将得到更新。
相同类型的 DOM 属性。
当元素类型相同时,react 将检查属性是否存在差异。如果 react 发现属性及其值有任何新变化,则它将仅更新已更改的属性。
<!-- Before --> <div className="someClass"> <Content /> </div> <!-- After --> <div className="someOtherClass"> <Content /> </div>
此处,只有 DOM 实例的类属性会得到更新。
相同类型的 DOM 属性(样式)。
当元素属于相同类型并且 React 发现样式属性存在差异时,它将仅更新样式的属性。
<!-- Before --> <div style={{fontFamily: 'Arial'}} /> <p> ... </p> </div> <!-- After --> <div style={{color: 'red', fontFamily: 'Arial'}} /> <p> ... </p> </div>
此处,只有 div 元素样式的颜色属性会被更新
相同类型的组件元素 − 每当 React 看到相同的 React 组件类型时,它就会调用 componentWillUpdate 事件和 React 组件的其他更新事件,以便组件更新其状态。然后,它将调用组件的 render 方法,算法会递归
相同类型的子元素集合 − 每当 React 看到相同类型的子元素集合时,它就会按顺序检查元素是否存在差异。因此,如果我们有一个新的第一个子元素,那么整个集合都会得到更新。
<!-- Before --> <ul> <li>Peter</li> <li>Olivia</li> </ul> <!-- After --> <ul> <li>John</li> <li>Peter</li> <li>Olivia</li> </ul>
此处,由于第一个元素 (li) 是更新元素,因此整个元素 (ul 元素的子元素) 将得到更新。
为了解决这个问题,我们可以引入一个 key 属性,如下面的代码片段所示。React 为此有一个特殊的 key 属性。
<!-- Before --> <ul> <li key="1">Peter</li> <li key="2">Olivia</li> </ul> <!-- After --> <ul> <li key="3">John</li> <li key="1">Peter</li> <li key="2">Olivia</li> </ul>
总结
React 尝试在每次发布中优化 diffing 算法,以确保更新最少。最少的更新意味着应用程序的性能更好。了解内部情况并遵循最佳实践进行相应的编码,我们可以成倍地提高应用程序的性能。