React-响应式系统|青训营笔记

119 阅读5分钟

这是我参与「第五届青训营」伴学笔记创作活动的第 6 天,欢迎各位大佬批评指正。

React 概述

React是目前最出色的前端框架之一,包括字节、阿里、腾讯、美团等多家大厂都在使用,许多网页也是基于React开发,比如:Facebook、Instagram、Netflix网页等。

React其实相对于传统的直接操作DOM编程的优势就在于将数据变动导致页面DOM更新的逻辑封装在框架内部,避免手动直接更改大量的页面DOM,大大提升了开发效率。所以React可以说是一个响应式的系统,并且内部会维护一个Virtual DOM,通过Diffing算法尽量复用DOM节点,提高生产环境运行效率。此外,组件化的设计模式和申明式编码也大大提高了开发效率和复用性。

React NativeElectron框架极大拓展了应用场景~

React 设计思路

React的出现是为了解决UI编程的痛点:

  1. 状态更新,UI不会自动更新,需要手动调用DOM来处理更新逻辑。
  2. 欠缺基本的代码层面的封装和隔离,代码层面没有组件化。
  3. UI之间数据没有依赖关系,需要手动维护,如果依赖链过长,会遇到回调地狱问题。

为了解决以上痛点,React做了以下设计:

1. 响应式与转换式

  • 转换式系统:给定输入,求解输出。比如:编译器系统。

  • 响应式系统监听事件,消息驱动。比如:监控系统,UI界面等。

具体分析一下前端代码的执行逻辑会发现,很少有需要大量计算的工作,更多的时候是在监听一个事件,如果发生立马执行回调,那么显然响应式系统更加适合作为设计模式。

2. 响应式编程

  • 状态更新,UI自动更新。
  • 前端代码组件化,提高复用性,封装性
  • 状态之间的互相依赖关系,只需要声明即可。

3. 组件化

  • 组件声明状态和UI映射
  • 组件组件的组合,或者原子组件
  • 组件Props/State两种状态。
  • 组件内部有私有状态State,内部的状态外部不可见。
  • 组件接受外部Props状态提供复用;父组件可以将状态传入组件内部
  • 组件依据当前的Props/State返回UI

4. 状态管理

原则上组件应该将状态封装在内部,但是很多业务场景都会需要共享状态的情况。那么由于React是单向数据流,如果需要共享的状态不是父子组件,一般这种情况会把状态上升到共同父组件身上,但是会造成的后果是状态一旦更新,父组件之下的每个子组件都会执行一遍render方法,极大影响性能。因此通常的解决方式是利用状态管理库,将状态抽离到组件外部保存维护。

5. 生命周期

截屏2023-02-13 01.36.31.png

组件挂载第一步先执行构造器函数;然后执行render方法返回Virtual DOM节点。当发生更新的时候,会依据会传入的PropssetStateforceUpdate参数计算新的返回值。当返回的Virtual DOM会在React内部通过Diffing算法对比更改节点,尽量提高复用。

React 实现

1. JSX语法

JSX语法本身不符合js语法规范,会经过ReactBabel转译成符合js语法规范的代码。如下图所示,左侧returnJSX语法代码,经过转译后如右图所示:

截屏2023-02-13 01.50.49.png

2. Virtual DOM

Virtual DOM是一种用于和真实DOM同步,并在js内存中维护的一个对象,它具有和DOM类似的树状结构,并且可以和DOM建立一一映射关系。它赋予了React声明式能力,使得从手动操作DOM更新中解放出来。

更新步骤大致如下:

截屏2023-02-13 01.56.26.png

3. Diffing 算法

最难的部分其实就是Diffing算法。希望更新次数足够少并且计算速度足够快,在这两个之间TradeOff。但是完美的最小Diffing算法,时间复杂度为O(n^3);用牺牲理论最小Diffing换取时间,可以得到O(n)复杂度的算法。

How to Diff?

遵循以下原则:

元素方式
不同类型的元素替换
同类型的DOM元素更新
同类型的组件元素递归

PS:React中如果一个父组件状态发生改变,子组件会递归render,非常影响性能。因此,如果组件公用状态,可以用状态管理库来解决,而不必将状态上升到父节点,节约性能。

React 状态管理库

截屏2023-02-13 02.14.19.png

1. 核心思想

因为状态应该放在组件内部,但是如果需要状态需要共享,就需要上升节点。但是可以将状态放在组件外部,利用状态管理库来进行共享。(但是有一个严重问题:会影响组件的复用性,会使得状态与外部库强耦合,因此最好不要在开发一个库中使用这种解决方案。

核心思想就是将状态抽离到组件外部,统一处理。

2. 推荐应用

  • Redux
  • xstate
  • mobx
  • recoil