【前端框架React】原理

React设计思想

1.原生JS

React相比于vue来说更接近原生JS,因为在react内部,jsx模板经babel转化后是一个对象,所有的操作都是基于这个对象和其对应的fiber结构来操作的,而vue.js通过编译将templete模板转换成渲染函数(render),执行渲染函数就可以得到一个虚拟节点树。

2.实现和更新原理

React将每个节点转化为fiber对象,最终形成一个fiber树结构,来依次渲染。通过两个fiber的对比来实现更新。这里要说到几个diff算法,分别是tree diff,component diff和element diff。同时更新过程可能会被打断,让优先级更高的任务优先执行(例如浏览器渲染)

TREE DIFF

核心是层次遍历和层级监控。如果同层有节点不同则会删除它的子树进行重新渲染,所以设置state要使粒度合适的小一些。能带来性能上的提升。

COMPONENT DIFF

如果某两个节点不是一个类型则进行TREE DIFF,否则进行ELEMENT DIFF。

ELEMENT DIFF

先根据每个节点的ID进行移位检查比较是不是同一个ID,并得到它如何进行增删查改。

3.单项数据绑定

父传子用props,有子传父的方法,不支持双向绑定,需要手动配置。

4.模板的格式和转换

用jsx指定模板,jsx类似JavaScript的扩展,在函数组件返回jsx,或者class组件的render方法内返回jsx,jsx将转换成对象。

5.关注运行时

React 更像是一种编程运行时。

React 程序通常会输出一个会随时间变化的树。 它有可能是 DOM 树 、iOS 视图层、PDF 原语 ,或者是 JSON 对象 。不过通常我们希望用它来展示 UI 。我们称它为"宿主树",因为它往往是 React 之外宿主环境中的一部分 ------ 就像 DOM 或 iOS 。宿主树通常有它自己的命令式 API 。而 React 就是它上面的那一层。

所以 React到底有什么用呢?非常抽象,它可以帮助你编写可预测的,并且能够操控复杂的宿主树进而响应像用户交互、网络响应、定时器等外部事件的应用程序。

他有以下两个特性

稳定性。 宿主树是相对稳定的,大多数情况的更新并不会从根本上改变其整体结构。如果应用程序每秒都会将其所有可交互的元素重新排列为完全不同的组合,那将会变得难以使用。那个按钮去哪了?为什么我的屏幕在跳舞?

通用性。 宿主树可以被拆分为外观和行为一致的 UI 模式(例如按钮、列表和头像)而不是随机的形状。

这些原则恰好适用于大多数 UI 。 不过当输出没有稳定的"模式"时 React 并不适用。

(其实我没有很理解......可以查看这篇文章,写的很好把React作为UI运行时来使用)

6.实例

(1)创建更新阶段

先执行React.createElement()函数将转化为一个ReactElement对象后,然后再执行ReactDOM.render()函数,这样就开始了ReactDOM的逻辑了。在ReactDOM.render里会经过一些列的初始化,创建一个fiber树。

我们可以把每个fiber理解为一个DOM对象的映射,绝大多数DOM对象都有一个其对应的fiber对象的(文本节点是没有fiber对象的,react直接通过nodeValue来设置了)。

创建一个React组件的方法

ReactDOM.render(<App/>,root)

babel转换后

React.createElement(React.createElement(App, null), null)

返回了一个对象

{

$$typeof:Symbol(react.element),//表示当前对象是一个ReactElement对象

type:App,

key:null,

ref:null,

props:{},

_owner:null

执行完创建更新阶段,之后就进入了React的任务调度阶段了。

(2)任务调度阶段

React中的任务分为同步和异步任务,如果是同步任务则会直接跳过这个阶段进入render阶段,对于异步任务来说,它会在浏览器渲染完之后利用空余的时间进行更新。

任务调度会利用requestAnimationFrame这个原生的API接口,requestAnimationFrame函数会在每次浏览器前执行的,执行的时候react利用了postMessage函数在任务队列里插入了一个函数,这样等到浏览器重绘完成后就会执行这个任务了,然后会触发相应的逻辑,执行第三步骤render阶段的相关操作。

总的来说会对fiber树单向遍历,父到子,子到孙,采用事件切片的任务调度方式,优先级高的任务和渲染先做,空闲时间做一些diff算法。

(3)render阶段

render阶段会依次遍历在第一步生成的fiber结构,利用深度优先遍历的算法,先遍历整个fiber树最左侧的fiber对象,然后再遍历到右侧的,最终回到最底层的根fiber对象,中间根据不同的组件类型做不同的处理,这个阶段也是整个React最难理解的一个阶段,因为有非常多的处理函数,还可以被高优先级的任务给打断,例如浏览器重绘,自定义事件等。这个阶段完成后在最顶层的fiber的firstEffect和lastEffect上设置一个链表,指向所有需要在commit阶段进行处理的fiber。

render采用深度优先遍历算法遍历形成的fiber结构。

(4)commit阶段

这个阶段比较简单,就是遍历第三步最后生成的Effect链,依次在每个fiber上执行收尾的工作。

相关推荐
To_OC10 小时前
LC 51 N 皇后:我以为难的是回溯,结果栽在了对角线下标
javascript·算法·leetcode
小林ixn12 小时前
从零到一理解 React 父子组件通信:手写一个 Todo 应用带你彻底搞懂单向数据流
前端·javascript·react.js
窝子面14 小时前
手搓最简前后端协作-node
javascript·数据库
qetfw14 小时前
MXU:Tauri 2 + React 的 MaaFramework 跨平台 GUI 源码
前端·python·react.js·前端框架·开源项目·效率工具
kyriewen15 小时前
我让AI给前端项目做了一次完整的Code Review——它和人类的差距,比我想的大得多
前端·javascript·ai编程
এ慕ོ冬℘゜15 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
hoLzwEge15 小时前
拯救低效调试!code-inspector-plugin 让代码定位如虎添翼
前端·前端框架·node.js
鱼毓屿御16 小时前
从「只会聊」到「边想边做」的跃迁
前端·学习·react.js
sugar__salt16 小时前
Vue3 表单双向绑定与响应式核心 API 技术详解
前端·javascript·vue.js
SmartBoyW17 小时前
CSS弹性布局(Flexbox)学习笔记:从零开始搞懂弹性布局
前端·javascript