深入理解React之React的工作原理(二)

·  阅读 55

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

深入理解React之React的工作原理(二)

1、Diff算法

  • tree diff:新旧DOM树,逐层对比的方式,就叫做 tree diff,每当我们从前到后,把所有层的节点对比完后,必然能够找到那些 需要被更新的元素;
  • component diff:在对比每一层的时候,组件之间的对比,叫做 component diff;当对比组件的时候,如果两个组件的类型相同,则暂时认为这个组件不需要被更新,如果组件的类型不同,则立即将旧组件移除,新建一个组件,替换到被移除的位置;
  • element diff:在组件中,每个元素之间也要进行对比,那么,元素级别的对比,叫做 element diff;
  • key:key这个属性,可以把 页面上的 DOM节点 和 虚拟DOM中的对象,做一层关联关系;

fiber是React 16中新的引擎。它的主要目的是使虚拟DOM能够进行增量渲染。

React Fiber 是对 React 核心算法的重新实现。

React Fiber 的目标是提高其对动画,布局和手势等领域的适用性。它的最重要的特性是 incremental rendering(增量渲染) :它能够将渲染 work 拆分成多块并将这些任务块分散到多个帧执行。

其他的核心特性还包括当新的更新到来时暂停、中止或恢复 work 的能力;为不同类型的更新设置优先级的能力;以及新的并发原语。

2、什么是 reconciliation?

reconciliation

  • reconciliation

    React 用来比较两棵树的算法,它确定树中的哪些部分需要被更新。

    • update

      用来渲染 React 应用的数据的改变。通常是 setState 的结果。最终结果将是一次重新渲染

    React 的 API 的核心理念是将更新想象成为对整个应用的重新渲染。这允许开发者声明式地推导,而不用担心应用如何从一个状态高效的过渡到另一个状态(A 到 B,B 到 C,C 到 A 等等)。

    实际上,对于每个更改重新渲染整个应用程序只适用于最简单的应用程序。在实际的应用中,对性能会有非常大的开销。

    Reconciliation 是被大家广泛知晓的 "virtual DOM" 背后的算法。

    • 不同的组件类型被认为将生成本质上不同的树。React 将不尝试去进行差异比较,而是直接完全替换旧的树。
    • 对于列表的差异比较使用 key 来优化性能。Keys 应当是稳定、可预测且唯一的。
  • Scheduling(调度)

    Scheduling

    • scheduling

      决定 work 何时应该被执行的过程。

    • work

      任何计算结果都必须被执行。Work 通常是更新的结果(e.g. setState).

      在 React 目前的实现中,React 递归地遍历树并且调用 render 方法在 event loop 的一次迭代中更新整棵树。不过在将来,它将延迟一些更新来防止掉帧。

      这是 React 设计中一个公共的主题。一些受欢迎的库实现了“推”的方法,计算会在新数据到来的时候被执行。但是 React 坚持“拉”的方法,计算能够被推迟直到需要的时候。

      React 不是一个通用的数据处理库。它只是设计来构建用户界面的库。我们认为知晓哪些计算是现在就相关的,哪些不是是在应用程序中有独一无二位置的内容。

      如果一些东西在屏幕外,我们可以推迟任何与其相关的逻辑。如果数据到来的速度比帧率块,那么我们可以合并并批量更新。我们可以对来自用户与界面互动的工作(如一个按钮点击的动画)和相对不太重要的背后工作(如远程加载数据渲染新的内容)进行优先级的排序来阻止掉帧。

    总结一下核心点如下:

    • 在 UI 中,并非所有的更新都需要立即生效。实际上,这样做是浪费的,可能会造成掉帧从而影响用户体验。
    • 不同类型的更新有不同的优先级。一个动画更新相比于来自数据的更新通常需要更快地被执行。
    • 一个以“推”为基础的方案要求应用程序(你,工程师)来决定如何调度工作。而一个以“拉”为核心的方案允许框架(如:React)更智能,来为你做这些决定。

    iber 的主要目标是让 React 能够享受到调度带来的好处。明确地说,我们需要能够做到以下几件事:

    • 暂停任务并能够在之后恢复任务。
    • 为不同的任务设置不同的优先级。
    • 重新使用之前完成的任务。
    • 如果不在需要则可以终止一个任务。

    为了做到这些事,我们首先需要一个方式来拆分这些任务为一个个任务单元。从某种意义上来说,这些任务单元就是 fiber。一个 fiber 代表了一个 任务单元.

    view = fn(data)
    复制代码

    因此渲染 React 应用程序就类似于调用一个包含其他函数调用的函数。

3、一切皆为组件

3.1 组件的生命周期

组件之间通过props 得到任何数据,都是只读的,不能重新赋值

jsx语法中的标签,并不是直接渲染到了页面上,而是先转换成了React.createElement 这样的js代码,然后再通过render渲染到了页面中

es6 class 类中 静态方法挂载到了constructor构造器中,实例方法挂载到了原型对象中

class Person {
   constructor(name,age){
       this.name = name
       this.age = age
  }
   // say 是实例方法
   say(){
       console.log('您好')
  }
   
   // info 是静态方法
   static info = 123 
}
​
class Chinese extends Person {
   // 使用extends 关键字实现继承,子类的constructor构造函数中,必须显示调用super()方法,这个super表示父类中constructor的引用
   constructor(name,age,color,lang) {
       super(name,age)
  }
}
​
var p1 = new Person('zs',12)
console.log(p1)
​
var c1 = new Person('ls',12,'yellow','汉语')
console.log(c1)
c1.say()
console.log(Chinese.info)
​
复制代码

react无状态组件和有状态组件的区别 无状态组件:无状态组件(Stateless Component)是最基础的组件形式,由于没有状态的影响所以就是纯静态展示的作用。一般来说,各种UI库里也是最开始会开发的组件类别。如按钮、标签、输入框等。它的基本组成结构就是属性(props)加上一个渲染函数(render)。由于不涉及到状态的更新,所以这种组件的复用性也最强。

有状态组件:在无状态组件的基础上,如果组件内部包含状态(state)且状态随着事件或者外部的消息而发生改变的时候,这就构成了有状态组件(Stateful Component)。有状态组件通常会带有生命周期(lifecycle),用以在不同的时刻触发状态的更新。这种组件也是通常在写业务逻辑中最经常使用到的,根据不同的业务场景组件的状态数量以及生命周期机制也不尽相同。

3.2 什么时候用 无状态组件?什么时候用有状态组件?

①、如果一个组件,只需要通过外界传递过来的props,渲染固定的页面,就适合使用function创建出来的无状态组件。

②、如果一个组件需要存放自己的私有数据,同时需要在组件的不同阶段执行不同的业务逻辑,就适合使用有状态组件。

在React中,我们通常通过props和state来处理两种类型的数据。props是只读的,只能由父组件设置。state在组件内定义,在组件的生命周期中可以更改。基本上,无状态组件使用props来存储数据,而有状态组件(也称为智能组件)使用state来存储数据。

总的来说:无状态函数式写法 优于React.createClass,而React.Component优于React.createClass。能用React.Component创建的组件的就尽量不用React.createClass形式创建组件。

在React中创建组件有三种方式:

  • ES5写法:React.createClass
  • ES6写法:React.Component
  • 无状态的函数写法,又称为纯组件

4、声明式编程

声明式与命令式

  • 命令式编程:命令“机器”如何去做事情(how),这样不管你想要的是什么(what),它都会按照你的命令实现。
  • 声明式编程:告诉“机器”你想要的是什么(what),让机器想出如何去做(how)。

jQuery是命令式的编程,jQuery让你去使用它的API,去做一些事情,如果jQuery的API改变了,我们写的的代码也要改变,因为API发生变化了,我们需要修改之前的API,所以这样的设计是很不友好的。

React中的写的code不大可能调用系统级别的API,相反,我们是实现一些函数,去响应,我们写的代码,只是声明我们要做什么,怎么去做,就是React来完成了,我们不用去关心,即使React的API改变了,也不会影响。

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改