day5 React | 青训营笔记

42 阅读5分钟

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

React历史与应用

React可以用于前端应用开发(FaceBook,Ins,网飞网页版),移动原生应用开发,也可以结合Electron进行桌面应用开发,也可以写3D的场景。

React的原型是FaxJS,其特性正是之后React的特性,第一个特性是写一次就可以在任何地方渲染(客户端或者服务端),第二个特性是随着状态改变,视图会自动更新

React设计思路

UI编程痛点

为了了解React设计思路,从原生的前端设计痛点出发,来看React是如何设计解决这些问题。用传统JS书写前端主要有以下痛点

  • 状态更新,UI 不会自动更新,需要手动地调用 DOM进行更新。
  • 欠缺基本的代码层面的封装和隔离,代码层面没有组件化。
  • UI 之间的数据依赖关系,需要手动维护。如果依赖链路长,一层层得调用,则会遇到"Callback Hell"

响应式与转换式系统

此外,前端其实是响应式系统。转换式系统和响应式系统是不同的,转换式系统有比如编译器,算法题,做的是给定输入求解输出的过程,而前端其实是属于响应式系统,主要做的是监听事件,消息驱动,是典型的异步编程,类似的响应式系统还有火灾报警器等。

响应式系统可以表示为:事件→执行既定的回调→状态变更;

具体到前端代码来讲多了一个步骤:事件→执行既定的回调→状态变更→UI更新;

由以上事实和痛点,我们希望react框架有如下特性:

对于第三条理解如下,如果想让a=b+c永远成立,b或者c改变时a也跟着改变,就需要声明式编程

组件化

下面看一个组件化的例子,在以下组件划分的实现中我们可以总结出三点

  1. 组件是组件的组合/原子组件
  2. 组件内拥有状态(颜色大小等),外部不可见
  3. 父组件可将状态传入组件内部(父组件可以通过对外暴露的接口控制子组件)

思考1:【当前价格】 状态应该属于谁? 答:应该属于Root节点,因为只有父组件可以控制子组件,顶栏和内容都需要共享【当前价格】状态,所以【当前价格】只能属于他俩最近的祖宗节点,即Root节点(小伏笔,需要用状态控制来解决状态上移的问题)

思考2:【当前价格】如何改变?

思考3:React 是单向数据流, 还是双向数据流?

答:是单向数据流,永远是父组件向子组件传东西,但不代表子组件不能改变父组件状态,因为父组件可以将函数传给子组件,

组件设计更详细的思路:

  1. 组件声明了状态和UI 的映射(根据当前的 State/Props, 返回一个UI)
  2. 组件有 Props/State 两种状态(组件内部拥有私有状态 State,外部不可见,也有从外部(向外暴露的接口)传入的状态,即接受外部的 Props 状态提供复用性) 3.“组件"可由其他组件拼装而成

想象一个组件结构如下,其中返回的不只是html还有子组件,subcomponent,该父组件可以为其传入color等props:

生命周期

组件有三个状态时间点,挂载的时候,卸载的时候,以及状态改变的时候,注意每次状态改变时,都会render重新计算改变UI。

React(hooks)的写法

  • Hooks:挂载到React组件生命周期上去执行的函数,比如useState挂载到状态改变时执行,useEffect在mount时,和依赖项被set时候执行;
  • hook使用法则:不能在循环,条件或嵌套函数中调用hook
  • 设置count时需要使用setCount函数,声明新变量使用[const, setCount] = useState(0);
  • 为了对父组件进行操作(比如网络请求等有确认的执行时间的动作),需要使用useEffect(),这个函数会在组件生成时使用一次

React Diffing

React利用虚拟DOM来间接操作DOM,更新网页时先对比之前的节点,只更新有变化的节点。

完美的最小Diff 算法,需要 O(n^3)的复杂度。 牺牲理论最小 Diff,换取时间,得到了O(n)复杂度的算法: Heuristic O(n) Algorithm:Diff算法就是从最高父级结点开始往下递归遍历,对比前后的节点,遇到不同类型的元素直接选择替换(包括子树),遇到同类型的DOM元素则选择更新(调用setAttribute等),遇到同类型的组件元素则继续递归

React状态管理库

React状态管理库的核心思想是将状态抽离到UI外部进行统一管理,这样无论在哪都可以获取store的状态,可以解决状态共享的问题,但他的最大的缺点在于,会降低组件的可复用性。所以store中最好只放需要共享的状态。常用的有redux、xstate、mobx、recoil等