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

96 阅读4分钟

这是我参与 「第五届青训营」 伴学笔记创作活动的第 2

1. React的应用

  1. 前端应用开发
  2. 移动原生应用开发
  3. 桌面应用开发

React并不是一个框架,它只是一个library

2. React的设计思路

之前UI编程的痛点: image.png 以IPHONE官网为例,在选择电子产品时,不同的配置组合的价格会不同,在显眼的地方会显示这个最终的价格,这个显示的价格与变量比如currentValue绑定,配置选择按钮绑定onclick事件,点击这些按钮后会执行回调函数修改currentValue的值,但是要修改显示的最终价格,还是需要获取dom元素后再进行修改。

总结以上内容:

  1. 状态值更新,UI不会自动更新,需要手动调用DOM进行更新。
  2. 欠缺基本的代码层面的封装和隔离,代码层没有组件化。
  3. UI之间的数据依赖关系需要手动维护(比如一个UI的值发生变化另一个UI的值也需要跟着改变),如果依赖链长,会造成回调地狱。

因此有了响应式系统:
响应式系统的流程如下:
事件发生 -> 执行既定的回调 -> 状态变更 -> UI更新

响应式编程以怎样的途径解决了UI编程的痛点:

  1. 状态值更新,UI自动更新;
  2. 前端代码组件化,可复用,可封装;
  3. 状态之间的相互依赖关系,只需声明即可。

image.png 按照响应式编程的思想,将上述例子可以拆分为一些组件(存在父子组件关系),currentValue位于root组件,因为组件的值通常由父组件传递到子组件内部及子组件共享父组件的值。所以状态归属于两个节点向上寻找到最近的祖宗节点。
并且,因为React是单向数据流,组件的值永远只能由父组件传递给子组件。如果在子组件中想要修改父组件的值,可以调用父组件中传递过来的函数。

根据以上的讨论,我们最终可以得出组件设计的最终思路:

  1. 组件声明了状态和UI的映射,状态的值能够保持与UI显示内容的一致性。
  2. 组件有Props(父组件传入的值)/State(本身的值)两种状态。
  3. “组件”可由其他组件拼接而成。

3. React的生命周期

image.png

4. React中基本的两个hook

其他hook都是以这两个hook为基础进行拓展

  1. useState
    例子:
    carbon (1).png useState实现在函数组件内部存储state。
  2. useEffect
    接受两个参数,一个为回调函数,一个是数组
    如果没有传入数组,那么回调函数仅仅会在组件挂载的阶段执行

5. React的实现

  1. 通过转移将不符合JS语法的JSX转义为能够被浏览器所识别是JS语法,例如:使用React.createElement替代return(<div></div>)
  2. 通过设置虚拟DOM对象,在返回的JSX发生变化时,高效地更新DOM image.png 其中最重要的是Diffing这个过程,需要在“更新次数少”和“计算速度快”之间找到对应的平衡。
    目前的替换规则: | 替换目标 | 替换方式名称 | 替换方式 | | --------- | -- | ---------------------------------------------------- | | 不同类型的元素 | 替换 | 如果是不同类型的元素,那么直接更新该元素及它的子元素 | | 同类型的DOM元素 | 更新 | 如果是同类型的元素,只是attribute(属性)发生了变化,那么调用setAttribute去更新属性 | | 同类型的组件元素 | 递归 | 通过递归方法往更深层次地走|

根据以上的规则,可以看出React的替换的话,需要从父组件到子组件一层层地去替换,如果只是树中间的部分发生了改变,这种方式是非常浪费时间的一件事。

 

6. React状态管理库

核心思想:
通过React状态管理库,将状态进行统一的管理,即将状态抽离到UI外部进行统一管理,这样就避免了为了让两个距离较远的元素共享同一个状态而把该状态放到根节点,但是这种方式比较适用于与业务相关的场景进行使用,如果是对于一些需要进行复用并且会控制组件内部功能的状态,还是应该放到组件内部。

使用:
一个单独的状态管理文件: carbon (3).png

在需要引用的jsx/tsx文件中:
const [ { x, y}, {incrementX, increment}] = useModel(countModel);