React 虚拟 DOM 及 Diff 算法

96 阅读3分钟
  • 虚拟DOM,再 React 中 DOM 的生成首先会创建一个 React 元素,将元素放置到对于生成的 React 根元素中,通过根元素的调用 Render 函数去创建对应的 DOM 元素;而虚拟 DOM 的初始生成,会先清除根元素下的所有内容,再生成真实 DOM,对于 DOM 元素数据内容的变化,会重新生成一个新的虚拟 DOM ,将新旧的虚拟 DOM 进行对比,父节点变化的话会进行删除再创建,没变化的话再进行子节点的对比

在React我们操作的元素被称为React元素,并不是真正的原生DOM元素,

React通过虚拟DOM 将React元素 和 原生DOM,进行映射,虽然操作的React元素,但是这些操 作最终都会在真实DOM中体现出来

虚拟DOM的好处:

  • 降低API复杂度
  • 解决兼容问题
  • 提升性能(减少DOM的不必要操作)

每当我们调用root.render()时,页面就会发生重新渲染

React会通过diffing算法,将新的元素和旧的元素进行比较

通过比较找到发生变化的元素,并且只对变化的元素进行修改,没有发生的变化不予处理

比较两次数据时,React会先比较父元素,父元素如果不同,直接所有元素全部替换

父元素一致,再去逐个比较子元素,直到找到所有发生变化的元素为止

新旧两组数据完全一致,所以没有任何DOM对象被修改

当我们在JSX中显示数组中,数组中每一个元素都需要设置一个唯一key,否则控制台会显示红色警告

重新渲染页面时,React会按照顺序依次比较对应的元素,当渲染一个列表时如果不指定key,同样也会按照顺序进行比较,

如果列表的顺序永远不会发生变化,这么做当然没有问题,但是如果列表的顺序会发生变化,这可能会导致性能问题出现

在列表的最后添加了一个新元素,并没有改变其他的元素的顺序,所以这种操作不会带来性能问题

在列表的最前边插入了一个新元素,其他元素内容并没有发生变化,

但是由于新元素插入到了开始位置,其余元素的位置全都发生变化,而React默认是根据位置比较元素

所以 此时,所有元素都会被修改

为了解决这个问题,React为列表设计了一个key属性,

key的作用相当于ID,只是无法在页面中查看,当设置key以后,再比较元素时,

就会比较相同key的元素,而不是按照顺序进行比较

在渲染一个列表时,通常会给列表项设置一个唯一的key来避免上述问题

(这个key在当前列表中唯一即可)

注意:

  • 开发中一般会采用数据的id作为key
  • 尽量不要使用元素的index作为key,索引会跟着元素顺序的改变而改变,所以使用索引做key跟没有key是一样的

唯一的不同就是,控制台的警告没了

当元素的顺序不会发生变化时,用索引做key也没有什么问题