React从入门到精通系列之(19)彻底理解React如何重新处理DOM(Diff
十九、彻底理解React如何重新处理DOM(Diffing算法)React提供了一个声明式的API,所以你不必担心每次DOM更新时内部会修改哪些东西。虽然在React中并不是那么明显地告诉你具体如何实现的,不过这也让编写应用变得更加容易。 本文会详细解释在React中的 动机当使用React时,在单个时间点,您可以将 对于将一个树变换成另一个树的最小操作数的算法问题,现在已经存在一些比较通用的解决方案。 然而,那些现有的最先进的技术算法都有 如果在React中使用这些算法,显示1000个元素将需要大约十亿次比较。 这个真的代价太昂贵了。 相反,React实现了一个
实际上,这两条假设对几乎所有的实际使用都是有效的。 Diffing算法当比较两棵DOM树的差异时,React首先比较两个根元素。 如果根元素的类型不同,那么行为也是不同的。 不同类型的DOM元素每当根元素是不同的类型时,React将删除旧的DOM树并从头开始重新构建新的DOM树。 从 当删除就的DOM树时,旧的DOM节点也被删掉。 这个时候组件实例触发 在根元素之下的任何组件将被卸载并且它们的 // 从 <div> <Counter /> </div> // 变为 <span> <Counter /> </span> 因为根元素从 相同类型的DOM元素当比较相同类型的两个React DOM元素时,React会先查看两者的属性差异,然后保留相同的底层DOM节点,仅仅去更新那些被更改的属性。 例如: <div className="before" title="hello" /> <div className="after" title="hello" /> 通过比较这两个元素属性,React就会知道只需要修改底层DOM节点上的 当更新 <div style={{color: 'red',width: '300px'}} /> <div style={{color: 'red',width: '400px'}} /> 当在这两个元素之间转换时,React知道只需修改 处理根DOM节点后,React会根据上面的判断逻辑对子节点进行递归扫描。 相同类型的组件元素当组件更新时,实例保持不变,因此在不同的渲染之间组件内的 接下来,调用 递归子元素默认情况下,当对DOM节点的子元素进行递归时,React只是同时迭代两个子元素lists,并在有差异时产生变化。 例如,当在子元素的末尾再添加一个元素时,这两个树之间就会有一个的很好转换效果: <ul> <l1>one</li> <li>two</li> </ul> <ul> <li>one</li> <li>two</li> <li>three</li> </ul> React将匹配两个 但是,不要太天真了。如果在子元素的开头部分插入一个元素的话,性能会便的很差。 例如,这两棵树之间的转换效果就很差: <ul> <li>one</li> <li>two</li> <ul> <ul> <li>zero</li> <li>one</li> <li>two</li> <ul> 这种情况React将更改每个子元素 ,而不会意识到它可以保持 keys为了解决上面的问题,React提供了一个 <ul> <li key="1">one</li> <li key="2">two</li> <ul> <ul> <li key="0">zero</li> <li key="1">one</li> <li key="2">two</li> <ul> 现在React就可以知道 在实践中,使用一个唯一的 <li key={item.id>{item.name}</li> 如果不是这样,你可以向数据模型中给每一项数据添加一个新的 最后一种方式是可以将数组中的索引作为 权衡利弊要记住重要的是, 在当前的实现中,你可以看到一个事实是一个子树已经成功移动到它的兄弟元素当中,但你不能告诉它已经移动到别的地方。 该算法将重新渲染这个完整的子元素树。 因为React很依赖这个直观推断的算法来判断DOM是否需要重新处理,如果不能满足这个算法的那两个假设条件前提,应用的性能将会受到很大影响。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |