这是我参与「 第五届青训营 」伴学笔记创作活动的第 6 天
本堂课主要讲解的重点内容
- React的历史与应用
- React的设计与实现
- React(hooks)的写法
- React的实现
- React状态管理库
- 应用级框架科普
对讲解的部分知识点进行介绍
一 React的历史与应用
1 React的历史
- 2010年Facebook 在其 php 生态中,引入了 xhp 框架,首次引入了组合式组件的思想,启发了后来的React的设计。
- 2011年Jordan Walke 创造了FaxJS,也就是后来的React原型:
- 2012年在Facebook 收购 Instagram 后,该 FaxJS 项目在内部得到使用, Jordan Walke 基于 FaxJS 的经验开发出了React
- 2014年-今天 生态大爆发,各种围绕React的新工具/新框架开始涌现:
2 React的应用
- 前端应用开发,如Facebook,Instagram,Netflix网页版
- 移动原生应用开发,如Instagram,Discord,Oculus
- 结合Eletron进行桌面应用开发
二 React的设计与实现
1 UI编程的痛点:
- 状态更新时UI不会随之自动更新,需要手动调用DOM接口进行更新
- 欠缺基本的代码层面的封装和隔离,代码层面没有组件化
- UI之间的数据依赖关系,需要手动维护,如果依赖链路长,则会遇到回调地狱 “callback hell”
2 响应式与转换式:
对于转换式系统无法完成的任务,响应式可以遇到事件,然后执行既定的回调,并更新状态和UI,即可实现效果:
graph LR
事件 --> 执行既定的回调 --> 状态变更 --> UI更新
- 转换式系统:给定输入,求解输出,如编译器、数值计算等
- 响应式系统:监听事件,消息驱动,如监控系统监控、UI界面更新等。
2.1 响应式编程
- 状态更新,UI也会进行更新
- 前端代码组件化,可复用,可封装
- 状态之间的互相依赖关系,只需声明即可
3 组件化:
- 组件是组件的组合/原子组件
- 组件内拥有状态,外部不可见
- 父组件可将状态传入组件内部(复用)props
3.1 组件设计
- 组件声明状态和UI映射
- 组件有Props(外部传入)/state(私有)两种状态:前者是父组件传入的数据,后者是组件内部维护的数据
- 组件可由其他组件拼装而成
4 状态归属问题:
Q:右上角的当前价格数据应当归属到哪个组件去管理?
A:根节点Root,因为这个属性会被多个子组件共享
这也导致了一个问题:当多个子组件需要共享数据的时候,就得将共享数据提升到父组件中。
Q:既然现在知道当前价格是由Root结点管理的,那子组件需要修改当前价格时该怎么办呢?
A:在javascript中,函数是一等公民,所以可以将函数也作为属性传递给子组件。那么就可以在Root组件中定义一个修改当前价格的函数onChangeValue(),然后将这个函数传给子组件(向下传递),当子组件需要修改当前价格时,就调用该函数即可。
Q:React是单向数据流,还是双向数据流?
A:React遵循从上到下的数据流向,即单向数据流(数据在某个节点被改动后,只会影响一个方向上的其他节点;父组件给子组件传递信息,子组件通过执行父组件传递的函数改变父组件的状态),数据主要从父节点传递到子节点(通过props)。如果顶层(父级)的某个props改变了,React会重渲染所有的子节点。单向数据流并非“单向绑定”,甚至单向数据流与绑定没有“任何关系”。
vue和ng都是双向数据流、VM双向数据绑定。而react是单向数据流,model层的数据流向view层。
点击可查看:React自定义双向数据流的实现方式
Q:如何解决状态不合理上升的问题?
A:进行状态提升,进行兄弟组件间的简单通信
Q:组件的状态改变后,如何更新DOM?
A:React并不会把更新的内容挂在真的DOM上,而是使用虚拟DOM,React提供了组件的一个私有的,其他任何组件没有权限改变的属性:state(状态),当组件内容需要变化,我们改变state的对应的值就可以了
5 生命周期:
- 挂载(Mounting):插入真实DOM
- 更新(Updating):重新渲染
- 卸载(Unmounting):移除真实DOM
三 React(hooks)的写法
【Hooks的几种类型图片】引用自:「React 进阶」 React 全部 Hooks 使用大全 (包含 React v18 版本 )
案例一:点击按钮使得count + 1,无需手动实现(更新状态、ui界面)
此方法会返回两个值:当期状态和更新状态的函数。效果同 this.state 与 this.setState,区别是 useState 传入的值并不一定要对象,并且在更新的时候不会把当前的 state 与旧的 state 合并
案例二:副作用(只在组件挂载的时候执行一次)- 有些操作会给组件外部造成影响:发起网络请求和外部系统做交互等等
四 React实现
❓❓❓三个问题❓❓❓
1 JSX不符合JS标准语法
2 返回的JSX发生改变时,如何更新DOM
Virtual DOM(虚拟DOM)
Virtual DOM是一种用于和真实DOM同步,而在JS内存中维护的一个对象,它具有和DOM类似的树状结构,并和DOM可以建立一一对应的关系。
它赋予了React声明式的API:您告诉React希望让UI是什么状态,React就确保DOM匹配该状态。这使您可以从属性操作、事件处理和手动DOM更新这些在构建应用程序时必要的操作中解放出来。
DOM操作非常耗费性能,用户体验会很差。只更新变化的部分,将diff传出,但同时也希望diff的时间复杂度较小:
完美的最小Diff算法,需要O(n^3)的复杂度。
牺牲理论最小Diff,换取时间,得到了O(n)复杂度的算法:Heuristic O(n) Algorithm
2.1 如何去diff
| 类型 | 方式 |
|---|---|
| 不同类型的元素 | 替换 |
| 同类型的DOM元素 | 更新 |
| 同类型的组件元素 | 递归 |
3 State/Props更新时,要重新触发render函数
个人总结
通过之前的学习以及今天的笔记我了解了什么是响应式系统以及相关的问题,知道了React作为一个经典响应式系统的发展历史和应用方向,包括它的设计思路。它使代码更具封装性,让DOM更加容易的被操控,大大方便了前端人的应用。