React基础—Diffing 算法

1. Diffing 算法

React是基于虚拟DOM树的,也就是要对比原来的结构和预期更新后的树结构。那么这个过程是怎么完成的,这里做一个简单的记录。

  • 从根节点开始比较,如果根节点为不同类型的元素时,React会拆卸原有的树并且建立起新的树。也就是会重建整个树结构。
  • 如果为相同类型的 React 元素时,React 会保留 DOM 节点,仅比对及更新有改变的属性。
  • 然后递归的完成对对子节点的对比操作;

而,为什么我们在使用数组map遍历的时候,必须指定一个key属性?
其实,这也是出于重建每个元素所带来的开销问题。比如下面的案例:

<ul>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

<ul>
  <li>Connecticut</li>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

在没有指定key的时候。在对比的时候,发现第一个节点发生了改变,对应需要重建,对应的第二个元素对比还是发生了改变,还是需要重建。而实际上,前两个子元素逻辑上来讲,重复了不需要重建。这里就会带来一些性能上的问题。

故而,引入了key后,为:

<ul>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

<ul>
  <li key="2014">Connecticut</li>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

值得注意的是:这个 key 不需要全局唯一,但在列表中需要保持唯一

下面,就上述两个案例来做一个简单测试:

class DiffTest extends Component {
    
    

    constructor() {
    
    
        super();
        this.state = {
    
    
            items: [
                {
    
    id: "0001", name: '张三'},
                {
    
    id: "0002", name: '李四'},
                {
    
    id: "0003", name: '王五'}
            ]
        }
    }

    handleClick = () => {
    
    
        const {
    
    items} = this.state
        let item = {
    
    id: Date().toString(), name:"新增"}
        this.setState({
    
    items: [item,...items]})
    }

    render() {
    
    
        const {
    
    items} = this.state
        return (
            <div>
                {
    
    
                    items.map((item, index) => {
    
    
                        return <li key={
    
    index}>{
    
    item.name} <input placeholder='请输入'/></li>
                    })
                }
                <button onClick={
    
    this.handleClick}>添加一个Item</button>
            </div>
        );
    }
}

注意到这里指定的key值数据的下标位置,即:

<li key={index}>{item.name} <input placeholder='请输入'/></li>

这个案例的效果就为,当我们新增一个Item的时候,其实并没有复用相同的Item元素,而是对其所有均进行了重建操作。直观的可以从下面的运行图看出:
在这里插入图片描述

输入的内容没有对应的保存在“张三”一行,所以所有的元素其实都发生了重建。相反的,如果将key指定为预定义的一个id字段,即:

<li key={item.id}>{item.name} <input placeholder='请输入'/></li>

此时的效果就是,输入的内容对应的在“张三”一行,这里就不再给出运行图。

2. 注意

  1. Key 应该具有稳定,可预测,以及列表内唯一的特质。不稳定的 key(比如通过Math.random()生成的)会导致许多组件实例和 DOM 节点被不必要地重新创建,这可能导致性能下降和子组件中的状态丢失。
  2. 这个 key 不需要全局唯一,但在列表中需要保持唯一。

猜你喜欢

转载自blog.csdn.net/qq_26460841/article/details/124992093