react底层原理

2023-01-11 20:49:09 浏览数 (1)

虚拟dom

虚拟dom是react的核心特性,它让react的渲染性能更高效。

js正常操作dom,会引起整个页面回流重排,性能差。

使用虚拟dom,会用js对象先模拟dom的更新,比对出实际更新的dom进行局部更新。

  • 执行过程:
  • React组件配合 state 创建一个虚拟DOM树
  • 根据虚拟DOM树,生成一个真正的 DOM 树,再渲染到页面中
  • 当 state 或者 props 变化时,根据新的数据生成一个新的虚拟DOM树
  • 将新旧虚拟 DOM 树进行对比,通过diff算法找到新旧虚拟DOM的差异点,最后将差异点更新到页面上

diff算法:

1、比较层级(tree diff),如果某节点不存在了,则连同该节点的后代全部删除,不再继续比较。

2、比较组件(component diff)

React对于组件的策略有两种方式,分别是类型相同和类型不同的组件

相同的直接继续比较组件内部的dom,不同的类型的会直接替换掉组件内部所有节点(可能虚拟DOM并没有任何变化,所以用户可以通过shouldComponentUpdate() 来判断是否需要更新)

3、比较节点(element diff),对于同一层级的子节点,通过唯一的key比较。如果更新的节点key在老集合里已存在,直接复用。没有的话,插入新节点

所以react不建议用index当key,因为增删等修改dom的操作,会导致index错乱,引发错误渲染的bug,就失去了diff算法的意义

合成事件

react有一套独特的事件机制,包括事件注册、合成、冒泡、派发等,这套机制称之为合成事件。

react合成事件不会直接绑在dom上,而是使用事件委托机制,将事件全部绑定在顶层root节点上。当组件挂载或卸载时,只需在root节点上增加或删除对应事件的监听。

合成事件的好处:

• 对事件进行归类,可以在事件产生的任务上包含不同的优先级

• 提供合成事件对象,抹平浏览器的兼容性差异

• 减少内存消耗,提升性能,不需要注册那么多的事件了,一种事件类型只在 Root上注册一次

原生事件先于React事件执行

JSX

在js里面写html是一件很舒服且效率很高的事情,而react通过jsx实现了。

要明白JSX的原理,需要先明白如何用 JavaScript 对象来表现一个 DOM 元素的结构

代码语言:javascript复制
1   <div class="app" id="appRoot">
2    <h1 class="title">欢迎进入React的世界</h1>
3       <p>
4          React.js 是一个帮助你构建页面 UI 的库
5       </p>
6  </div>
7
8上面这个 HTML 所有的信息我们都可以用 JavaScript 对象来表示:
9
10 {
11   tag: "div",
12   attrs: { className: "app", id: "appRoot"},
13   children: [
14   	  {
15   		tag: "h1",
16   		attrs: { className: "title" },
17   		children: ["欢迎进入React的世界"]
18   	 },
19   	{
20   	    tag: "p",
21   		attrs: null,
22   		children: ["React.js 是一个构建页面 UI 的库"]
23   	}
24      ]
25}
26

react打包编译的过程会把类似 HTML 的 JSX 结构转换成 JavaScript 的对象结构

主要通过React.createElement()实现转换过程

代码语言:javascript复制
1//React.createElement` 会构建一个 JavaScript 对象来描述你 HTML 结构的信息
2//包括标签名、属性、还有子元素等
3React.createElement(
4    type,  (必填,代表的是标签名,eg: ul)
5    [props], (选填,代表属性,像className什么的)
6    [...children] (选填,子节点,eg:要显示的文本内容 )
7)     
8//举例:
9React.createElement("h1", {className: "main"}, "Hello React (method 2)");

示例:

代码语言:javascript复制
1import React from "react";
2import ReactDOM from "react-dom";
3
4class App extends React.Component {
5  render() {
6    return (
7      <div className="app" id="appRoot">
8        <h1 className="title">欢迎进入React的世界</h1>
9        <p>React.js 是一个构建页面 UI 的库</p>
10      </div>
11    );
12  }
13}
14ReactDOM.render(<App />, document.getElementById("root"));
15

编译之后将得到这样的代码:

代码语言:javascript复制
1import React from "react";
2import ReactDOM from "react-dom";
3class App extends React.Component {
4  render() {
5    return React.createElement(
6      "div",
7      {
8        className: "app",
9        id: "appRoot",
10      },
11      React.createElement("h1", { className: "title" }, "欢迎进入React的世界"),
12      React.createElement("p", null, "React.js 是一个构建页面 UI 的库")
13    );
14  }
15}
16
17ReactDOM.render(React.createElement(App), document.getElementById("root"));

想使用jsx有两种方式

  • 在.jsx文件中引入React
  • 配置babel,达成无需引入react就可以在.js中使用jsx

0 人点赞