共计 700 个字符,预计需要花费 2 分钟才能阅读完成。
前言:
关于 react 的虚拟 dom 以及每次渲染更新的 dom diff,网上文章很多。但是我一直信奉一个原则,即:但凡复杂的知识,理解之后都只需要记忆简单的东西,而想简单、精确描述一个复杂知识,是极困难的事。
正文
dom diff 是什么?1. 从根节点开始遍历所有节点;2. 对于不同类型的标签,删除原标签,新建标签;3. 对于类型相同、属性不同的标签,只修改属性;4. 对于同一个父节点下的复数同类型标签(即列表类型),基于 key 对比、修改。
解析
关于 1:
- 遍历用的是前序遍历(先序遍历)
关于 2:
- 不同类型的标签是指:比如 div 和 span 就是不同类型的标签 - 如果同一个位置的标签类型改变(依然以 div 和 span 为例),那么直接删除 div 标签,新建一个 span 标签,重新渲染。原本的 div 标签里的一切都跟新的 span 标签没有关系 - 对于自定义的组件比如 <Header />、<TodoList /> 之类的也适用 - 标签位置只相对于父节点有意义。假设原本 A 节点的父节点是 B,更新后 A 节点的父节点是 C,那么对于 dom diff 来说,原本的 A 节点会被销毁,在 C 节点下的 A 节点是一个新的节点,跟原本的 A 节点没有关系
关于 3:
- 这一个比较好理解,对于仅仅属性不同的标签,修改属性即可
关于 4
- 假设一个 div 下有五个 span 节点,此时我们要插入一个节点
虚拟 dom 并不知道插入后是 ABFCDE,而会认为除了 AB 以外的节点都改变了所以对于虚拟 dom 来说此时是 ABGHIJ,付出了额外的消耗。于是 react 引入了 key 的概念。两个 key 相同的节点,虚拟 dom 会认为是同一个节点,从而对其进行比较。引入了 key 之后,react 就知道节点是 ABFCDE 了。