【React】02-如何理解React通过对DOM的模拟,最大限度地减少与DOM的交互

2024-01-03 18:08:55

如何理解React通过对DOM的模拟,最大限度地减少与DOM的交互

背景

在学习React的过程中,发现很多文档上关于React的高效都有这么一句话的描述——React通过对DOM的模拟,最大限度地减少与DOM的交互,对于我这种前端小白来说,理解起来还是挺费劲的,所以找了些文档学习了一番。

分析

在查找资料的过程中,笔者发现关于这句话的描述其实包含着下面的知识点:

  • 虚拟DOM: React引入了虚拟DOM的概念。虚拟DOM是一个存在于内存中的树形结构,它对应着实际的DOM树。在React中,组件的状态变化会首先在虚拟DOM上进行操作,而不是直接操作实际的DOM。

关于虚拟DOM

这里我们先以一个计数器为例子,分别看看React和JavaScript对它的实现方式:
React实现方式

  1. 封装Counter.js
import React from "react";


// 计数器组件
const Counter = ({ count, onIncrement }) => (
  <div>
    <p>Count: {count}</p>
    <button onClick={onIncrement}>Increment</button>
  </div>
);

export default Counter;
  1. 在App.js中引入组件
function App() {
/**计数器组件 */
  const [count, setCount] = useState(0);

  // 处理递增事件
  const handleIncrement = () => {
    setCount(count + 1);
  };
  return (
    <div>
      <h1>Counter App</h1>
      <Counter count={count} onIncrement={handleIncrement} />
    </div>
  );
}

export default App;

JavaScript实现方式:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Counter App</title>
  </head>
  <body>

    <div id="counterContainer">
      <p id="countDisplay">Count: 0</p>
      <button id="incrementButton">Increment</button>
    </div>

    <script>
      // 获取DOM元素
      var countDisplay = document.getElementById('countDisplay');
      var incrementButton = document.getElementById('incrementButton');

      // 初始化计数器
      var count = 0;

      // 处理按钮点击事件
      function handleIncrement() {
        count++;
        countDisplay.textContent = 'Count: ' + count;
      }

      // 添加按钮点击事件监听器
      incrementButton.addEventListener('click', handleIncrement);
    </script>

  </body>
</html>

对比上面两种实现方式,JavaScript 直接对实际DOM进行操作,需要我们手动管理状态和UI之间的同步,每次计数+1时,同步修改UI展示。随着项目越来越大,当我们直接修改的DOM改动的频次越多,甚至涉及位置变换,那么就可能带来重排和重绘的问题了**。**

  1. 重排: 当改变影响到页面布局的属性时,例如修改了元素的尺寸、位置、添加或删除了DOM元素等,浏览器可能会触发重排。重排是一项比较昂贵的操作,因为它涉及到重新计算元素的几何属性和页面的布局,可能导致整个页面的重新渲染。
  2. 重绘: 当改变影响到元素的样式(但不涉及布局的改变)时,例如修改了颜色、背景等,浏览器可能会触发重绘。重绘相对于重排来说开销较小,因为它只涉及到重新绘制元素的外观。

再来看看React的实现方式,首先我们可以知道所有的HTML的DOM节点都可以用JS方式去表示,而React在这里巧妙的利用JS 表示 DOM对象的方式,避免了对DOM的直接操作,类似于中间加了一层缓存操作。(这里又想到一句话,计算机领域大部分问题都可以通过中间加一层解决)。如图所示,通过react-developer-tools工具,我们可以更加直观看到React如何表示我们的HTML的DOM结构。

image.png
React这种在内存中,采用JS 表示 DOM对象的方式,又有一个更加专业点的名称虚拟DOM。它通过采用虚拟DOM差异算法来最小化对实际DOM的直接操作。

以上面计时器为例,React在渲染过程中,会首先根据render的结果将这个树状结构在JS里创建出来,这个树状结构就是虚拟DOM层,当我们的计数器发生变化时,React会将这个新的虚拟DOM和正在呈现的虚拟DOM进行对比,并找出其中的差异,然后用最少的DOM操作完成这个更新

再回到我们的标题**如何理解React通过对DOM的模拟,最大限度地减少与DOM的交互?**这里我们可以做一下小结了,React通过引入虚拟DOM,当DOM发生修改时,在内存中进行差异对比,最大限度地的用最少的DOM操作完成这些操作。

随着深入了解,除去DOM,关于这句话的理解,其实也还包含了如下几个知识点,这里先列举出来:

  1. 批处理: React会将一系列对虚拟DOM的操作合并成一个批处理。这样可以减少实际DOM操作的次数,从而提高性能。React通过一些策略,例如合并相邻的setState调用,来优化实际DOM的更新。
  2. 差异算法(Reconciliation): 在组件状态发生变化时,React会通过比较新旧虚拟DOM树的差异,找出最小的更新操作。然后,只对实际需要更新的部分进行DOM操作。这就是所谓的“协调”(Reconciliation)过程。
  3. DOM更新的延迟执行: React会尽量将DOM更新的执行时机延迟到最合适的时候。例如,在浏览器的空闲时期,或者通过使用 requestAnimationFrame 等API来调度更新,以确保更新不会影响用户的交互体验。

文章来源:https://blog.csdn.net/legendaryhaha/article/details/135366888
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。