0208dom的diffing算法-react(代码片段)

gaog2zh gaog2zh     2023-03-29     772

关键词:

1 React DOM Diffing算法

1.1 原理

React DOM Diffing算法是React用来优化Virtual DOM更新性能的一种算法。当React中的组件状态发生变化时,React会使用Virtual DOM来进行快速的DOM更新。然而,由于Virtual DOM的渲染开销,React需要在Virtual DOM中执行一些优化策略来减少更新次数。

React的DOM Diffing算法的基本思路是比较两个不同状态的Virtual DOM树,找到最小的变化,并将其应用到实际的DOM树中。这个算法将Virtual DOM树分解成一个个的节点,并将它们逐一比较。比较过程中,React会尽可能地复用已有的DOM节点,避免重新创建DOM节点,从而减少渲染的成本。

React的DOM Diffing算法具体的实现步骤如下:

  1. 如果根节点不同,直接替换整个根节点。
  2. 如果节点类型不同,直接替换整个节点。
  3. 如果节点类型和key都相同,则比较节点的属性和子节点。
  4. 如果节点类型相同但key不同,则替换整个节点。
  5. 如果节点类型相同但属性不同,则更新属性。
  6. 如果节点类型相同但子节点不同,则递归比较子节点。

通过这些优化,React可以在保持应用程序的状态更新的同时,避免不必要的DOM操作,提高渲染性能。

1.2 测试

测试代码如下1.2-1所示:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>1301_验证Diffing算法</title>
</head>

<body>
  <div id="test"></div>
  <!-- react核心库 -->
  <script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
  <!-- 用于支持react操作DOM -->
  <script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
  <!-- 用于将jsx转为js -->
  <script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>

  <script type="text/babel">

    /**
     * 
     */
    class Time extends React.Component 

      state = date: new Date()
      

      componentDidMount() 
        setInterval(() => 
          // 更新状态
          this.setState(date: new Date())
        , 1000);
      

      /**
       * 初始化渲染,状态更新重新渲染
       */
      render() 
        return (
         <div>
          <h2>hello</h2>
          <input type="text"/> <br/>
          <span>
            现在是:this.state.date.toTimeString()
            <input type="text"/> <br/>
          </span>  
         </div>
        )
      
    

    // 2.渲染虚拟DOM到页面
    ReactDOM.render(<Time/>, document.getElementById('test'))

  </script>
</body>

</html>

测试效果如下图1.2-1所示:

2 React 中key

2.1 key的作用

在React中,key是用于帮助React识别组件中子元素的唯一标识符。当React更新组件时,React会使用key来判断哪些子元素已经发生变化,从而减少不必要的DOM操作,提高渲染性能。

具体来说,当React渲染组件时,它会生成一个Virtual DOM树。Virtual DOM是一个轻量级的JavaScript对象,用于描述实际的DOM结构。当组件的状态发生变化时,React会比较新旧Virtual DOM树之间的差异,然后将差异应用到实际的DOM树上。

在比较Virtual DOM树时,React使用key来识别哪些子元素已经发生变化。如果两个元素具有相同的key,则React会认为它们是同一个元素,并将其重用。如果两个元素的key不同,则React会将其视为两个不同的元素,并重新创建DOM节点。因此,使用正确的key可以帮助React减少DOM操作次数,提高渲染性能。

除了性能方面的考虑,key还可以帮助开发者维护组件的内部状态。在一些需要对组件进行增删操作的场景中,使用key可以确保每个子元素的状态正确地被保留和更新。

Diff对比的最小粒度上标签

2.2 key的取值

在React中,key应该是具有稳定、唯一和可预测性的值。这有助于React识别子元素并减少不必要的DOM操作,提高渲染性能。

通常情况下,key的取值有以下几种方式:

  1. 使用唯一ID(推荐):如果每个子元素都有唯一的ID属性,那么可以使用ID作为key的取值。这样可以确保每个子元素都有一个唯一的key。
  2. 使用索引:如果没有唯一ID,可以使用数组索引作为key的取值。但是,需要注意的是,如果数组中的元素顺序发生变化,那么key也会随之变化,这可能会导致不必要的DOM操作。
  3. 使用唯一的字符串:如果没有唯一ID和数组索引,可以使用唯一的字符串作为key的取值。可以使用UUID或其他生成唯一字符串的方法。
  4. 使用其他唯一属性:如果子元素具有其他唯一属性,例如用户名或电子邮件地址,可以使用这些属性作为key的取值。

需要注意的是,尽管可以使用各种方法生成key的值,但必须确保每个key都是唯一且稳定的。如果key的取值不稳定或重复,可能会导致React无法正确地识别子元素,并且可能会导致不必要的DOM操作,从而降低渲染性能。

用index作为key可能引发的问题:

  1. 若对数据进行: 逆序添加、逆序删除的功能破坏顺序操作:会产生没有必要的真实DOM的更新,即界面没效果,但效率低。
  2. 如果结构中还保护输入类DOM:会产生错误DOM更新
  3. 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅渲染列表用于展示,使用index作为key是没有问题的。

测试代码2.2-1如下所示:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>1301_验证Diffing算法</title>
</head>

<body>
  <div id="test"></div>
  <!-- react核心库 -->
  <script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
  <!-- 用于支持react操作DOM -->
  <script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
  <!-- 用于将jsx转为js -->
  <script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>

  <script type="text/babel">

    /**
     * 
     */
    class Person extends React.Component 

      state = 
        persons: [
          id: 1,name: '小张', age: 22,
          id: 2,name: '小王', age: 32,
        ]
      
      

      add = () => 
        const persons = this.state
        const p = id: persons.length+1,name: '小丽', age: 25
        this.setState(persons: [p, ...persons])
      

      /**
       * 初始化渲染,状态更新重新渲染
       */
      render() 
        return (
         <div>
          <h2>展示人员信息</h2>
          <button onClick=this.add>添加新成员</button>
          <h3>使用index(索引)作为key</h3>
          <ul>
            
              this.state.persons.map((p,index)=> 
                return <li key=index>
                  p.name----p.age&nbsp;
                  <input type="text"/>
                </li>
              )
            
          </ul>
          <hr/>
          <h3>使用id(数据唯一标识)作为key</h3>
          <ul>
            
              this.state.persons.map((p)=> 
                return <li key=p.id>
                  p.name----p.age&nbsp;
                  <input type="text"/>
                </li>
              )
            
          </ul>
         </div>
        )
      
    

    // 2.渲染虚拟DOM到页面
    ReactDOM.render(<Person/>, document.getElementById('test'))

  </script>
</body>

</html>
  • index作为key逆序添加导致全部已有标签的key+1,改变;那么对比相同key时,标签内容不一致,会重新渲染。所以页面上好像没啥问题,但是效率很低。
  • 如果有子元素,会导致数据错乱。

添加新元素前效果如下下2.2-1所示:

添加新成员后效果图示如下2.2-2所示:

结语

❓QQ:806797785

⭐️源代码仓库地址:https://gitee.com/gaogzhen/react-study

参考:

[1]React视频教程[CP/OL].2020-12-15.p48.

[2]React官网[CP/OL].

[2]ChatGPT[CP/OL].

react的diffing算法(面试题)(代码片段)

React的diffing算法在虚拟DOM转为真实DOM的时候,会想通过diffing算法进行一个比较。如果已经渲染过一次了,再次渲染的时候,会对相同key值的节点进行比较,如果内容相同,就会复用原来的那个真实DOM。经典面... 查看详情

react的diffing算法(面试题)(代码片段)

React的diffing算法在虚拟DOM转为真实DOM的时候,会想通过diffing算法进行一个比较。如果已经渲染过一次了,再次渲染的时候,会对相同key值的节点进行比较,如果内容相同,就会复用原来的那个真实DOM。经典面... 查看详情

diffing算法以及key值的作用(代码片段)

在react/vue中key有什么作用?内部原理是什么?一.虚拟dom中key的作用简单的来说key就是虚拟dom对象中的标识,在更新显示时key有很重要的作用原理:当状态中的数据发生改变的时候,react会根据【新数据】生成... 查看详情

react基础

...用React语法进行移动端开发3.使用虚拟DOM+优秀的Diffing算法,尽量减少与真实DOM的交互虚拟DOM和真实DOM的差别虚拟dom:1.本质式object类型的对象(一般对象)2. 查看详情

react入门学习--diffing算法(代码片段)

...c;一名大二的前端爱好者📢这篇文章将尽力说明白diff算法📢愿你忠于自己,热爱生活前言diff算法是React提升渲染性能的一种优化算法,在React中有着很重要的地位,也不止于React,在Vue中也有diff算法,... 查看详情

react入门学习--diffing算法(代码片段)

...c;一名大二的前端爱好者📢这篇文章将尽力说明白diff算法📢愿你忠于自己,热爱生活前言diff算法是React提升渲染性能的一种优化算法,在React中有着很重要的地位,也不止于React,在Vue中也有diff算法,... 查看详情

react学习(代码片段)

...用React语法进行移动端开发3.使用虚拟DOM+优秀的Diffing算法,尽量减少与真实DOM的交互虚拟DOM和真实DOM的差别虚拟dom:1.本质式object类型的对象(一般对象)2. 查看详情

虚拟 dom 和脏检查之间的性能差异

...dom和angular的脏检查之间的性能差异。React使用“diffing”算法。一个。它是如何工作的?湾。它是否保留twocopiesoftrees?比较两棵树不是很昂贵吗 查看详情

react入门(代码片段)

...用Reac语法进行移动端开发。使用虚拟DOM+优秀的Diffing算法,尽量減少与真实DOM的交互。虚拟DOM无须真实DOM上那么多属性。安装npmireactreact-domreact包是核心,提供创建元素、组件等功能react-dom包提供DOM相关功能等基本使... 查看详情

react入门(代码片段)

...用Reac语法进行移动端开发。使用虚拟DOM+优秀的Diffing算法,尽量減少与真实DOM的交互。虚拟DOM无须真实DOM上那么多属性。安装npmireactreact-domreact包是核心,提供创建元素、组件等功能react-dom包提供DOM相关功能等基本使... 查看详情

react虚拟dom与diff算法

...,不能实现跨端应用)。       (2)Reactdiff算法的实现。二、React中的diff算法  react的diff算法步骤如下:    1、(treediff)将react中的树形结构每一层结构进行比较,如果其中一个节点被删除,不用比较这个节... 查看详情

react虚拟dom与diff算法(代码片段)

...极速渲染的特点,这个特点依靠的就是react的虚拟dom和diff算法对比两个图就可以发现标准dom机制下,用户在应用上的操作是直接对真实dom进行操作的,在react中我们操作的是虚拟dom,用户的操作产生的数据改变或者state变量改变... 查看详情

深入理解react中的虚拟domdiff算法

...章结构:React中的虚拟DOM是什么?虚拟DOM的简单实现(diff算法)虚拟DOM的内部工作原理React中的虚拟DOM与Vue中的虚拟DOM比较 React中的虚拟DOM是什么?  虽然React中的虚拟DOM很好用,但是这是一个无心插柳的结果。   ... 查看详情

react之dom的diff算法(代码片段)

文章目录DOM的diff算法react中的key有什么作用?为什么遍历列表时,key最好不要用index?开发中如何选择key?实例总结DOM的diff算法React展示前端首先将DOM转换为虚拟DOM,然后再生成页面上的真实DOM,因此当DOM更新... 查看详情

react:虚拟dom和diff算法

虚拟DOM:概念:用JS对象的形式来模拟页面上DOM嵌套关系。(即虚拟DOM是以JS对象的形式存在的)本质:用JS对象模拟DOM元素和嵌套关系。目的:为了实现页面元素的高效更新。Diff算法:? 查看详情

react虚拟domdiff算法

react虚拟dom:依据diff算法台前端:更新状态、更新视图;所以前端页面的性能问题主要是由Dom操作引起的,解放Dom操作复杂性刻不容缓因为:Dom渲染慢,而JS解析编译相对非常非常非常快!jsg更容易表示节点所以:把js和html混写... 查看详情

react学习(代码片段)

...用React语法进行移动端开发3.使用虚拟DOM+优秀的Diffing算法,尽量减少与真实DOM的交互虚拟DOM和真实DOM的差别虚拟dom:1.本质式object类型的对象(一般对象)2.虚拟dom比较‘轻’,真实dom比较‘重’,因为... 查看详情

极品-react中的dom虚拟dom,与deff算法,router(代码片段)

...变化的时候(setState())他会生成一个新的虚拟DOM树通过deff算法计算上一次的值和新更新的值有什么新的变化最后render只会将更新的内容渲染到真实DOM上安装安装react-router-domyarnaddrea 查看详情