这是我参与2022首次更文挑战的第11天,活动详情查看:2022首次更文挑战
授课老师:露脸的牛岱老师
React 前置知识
- HTML,CSS,JS基础。
- 基础的数据结构/算法知识,如二叉树,深度遍历等。
- 会适用浏览器提供的DOM API来修改DOM,更新UI。
内容概要
- React的历史与应用
- React的设计思路
- React (hooks) 的写法
- React的实现
- React状态管理库
- 应用级框架科普
01.React 历史与应用
历史
- 启发: 10年facebook引入的php框架 xhp,这种组合式组件思想是React的启发。
- 原型: 11年FaxJS诞生于Jordan Walke之手,这是React最初的原型。
- Seamless Client Server Rendering
- Write once, render anywhere - client or server
- Reactive
- Views are automatically updated on state changes - no bindings necessary
- Performant
- Fast rendering using string concatenation, small code size
- Structural
- High level components, functionally defined, declarative views
- 开源:Jordan Walke开源React。
- 生态大爆发: 2014 - 至今。各种围绕React的新工具/新框架开始涌现。
应用
热知识:字节大部分前端体系都是React🤡
- 前端应用开发,如Facebook,Instagram,Netflix网页版。
- 移动原生应用开发,如Instagram,Discord,Oculus。
- 结合Electron,进行桌面应用开发。
React swiper 3D图形库
02.React的设计思路
推演React的设计思路
问题:通过选择各种选项,通过回调修改变量currentValue。但是还需要通过DOM去重新渲染当前价格。
总结:UI编程痛点。
- 状态更新,UI不会自动更新,需要手动地调用DOM进行更新。
- 欠缺基本的代码层面的封装和隔离,代码层面没有组件化。
- UI之间的数据依赖关系,需要手动维护,如果依赖链路长,则会遇到“Callback Hell”。
响应式与转化式
转换式系统和响应式系统一样吗?
转换式系统:我们学的编译原理,算法,抽象起来都可以说转换式系统的体现,这是一种给定输入,求解输出的过程。
响应式系统:类似于监控系统和上述的UI界面,我们更加关注的是如何监听事件以及监听事件后如何进行消息驱动,即当事件发生后需要做什么。
响应式系统的执行流程:
graph TD
事件 --> 执行既定的回调 --> 状态变更
对应到我们所说的前端UI界面,只需要在状态变更后额外增加UI更新的步骤即可。
graph TD
事件 --> 执行既定的回调 --> 状态变更 --> UI更新
响应式编程
响应式编程有哪些特点?
- 状态更新,UI自动更新。
- 前端代码组件化,可复用,可封装。
- 状态之间的互相依赖关系,只需要声明即可。
怎么理解这里的“声明”:比如我需要a永远等于b+c,那么,当b或者c任何一个变量改变时,a变量会自动更新。不需要我去额外调用一个函数来更新a的值。
组件化
接回之前说过的UI问题。我们可以给手机界面划分成一个个组件,其中组件可以嵌套子组件:
graph TD
root --> 内容 --> 配置面板 --> 型号选择 --> iPhone13
root --> 顶栏
内容 --> 橱窗
配置面板 --> 颜色选择
型号选择 --> iPhone13_Pro
颜色选择 --> 红
颜色选择 --> 橙
注意:上面不是一棵DOM树,只是为了清晰地区分组件,进行的人为划分。
总结:
- 组件是组件的组合/原子组件
- 组件内拥有状态,外部不可见
- 父组件可将状态传入组件内部
状态归属问题
问题: 当前价格应该属于哪一个节点?
答: Root,所有的子组件需要共享的数据都需要放置在父组件中。
问题:如果所有的子组件的数据都给父组件管理,可以吗???
答:尽可能保证局部性。(状态上升)状态归属于两个节点向上寻找的最近公共祖先。
问题:在子组件中修改对应选项,如何在Root中修改当前价格?
答:向子组件传递函数,在子组件的选择上触发回调,调用传递的函数。
思考
- React是单向数据流,还是双向数据流?
只能父传子,所以是单向数据流。
- 如何解决状态不合理上升的问题?
通过状态管理库来解决该问题。
- 组件的状态改变后,如何更新DOM?
这里需要使用一些DOM更新算法(DIFF)来判断并对对应的DOM进行更新。
组件化设计
所以,为了解决UI痛点,我们的组件需要设计成什么样子?
-
组件声明了状态和UI的映射。
-
组件有Props/ State两种状态。
-
“组件”可由其他组件拼装而成。
那么,对应的组件代码是什么样子?
- 组件内部拥有私有状态State。
- 组件接受外部的Props状态提供复用性。
- 根据当前的State/ Props,返回一个UI。
(下面是老师给出的想象,并非是react的语法。)
组件的生命周期
React组件的生命周期主要有三个时间点:挂载Mounting,更新Updating,卸载Unmounting。
03. React (hooks)的写法
代码1:封装更新
代码2:副作用(网络请求,影响外部,使用useEffect())
hook使用法则
- 不要在循环,条件或嵌套中使用hook
04.React的实现
Problems
- JSX不符合JS标准语法。
- 返回的JSX发生改变时,如何更新DOM?
- State/Prop更新时,如何重新触发render?
针对第一个问题: JSX语法的本质:还是以 React.createElement 的形式来实现的,并没有直接把用户写的HTML代码,渲染到页面上;
第二个问题:
Virtual DOM (虚拟DOM) Virtual DOM是一种用于和真实DOM同步,而在JS内存中维护的一个对象,它具有和DO M类似的树状结构,并和DOM 可以建立一一 对应的关系。 它赋予了React声明式的API:您告诉React希望让UI是什么状态,React 就确保D OM匹配该状态。这使您可以从属性操作、事件处理和手动D OM更新这些在构建应用程序时必要的操作中解放出来。
真实的DOM不是JS的对象。我们是通过操作DOM的接口来更新DOM的。
声明式编程 / 指令式 / 响应式编程的区别?
浏览器需要更高层的抽象。
父组件下的所有子组件都需要更新。
完美的最小Diff算法,需要O(n^3)的复杂度。
牺牲理论最小Diff,换取时间,得到了0 (n)复杂度的算法:启发式算法。
Heuristic O(n) Algorithm
类型不同替换--属性不同更新--存在子组件递归
05.React状态管理库
核心思想:将状态抽离到UI外部进行统一管理。
降低组件的复用性,强耦合。
redux:用得多,但是最近设计有些问题。
const [{x,y},{incrementX,incrementY}] = UseModel(countModel);
06. 应用级框架科普
- NEXT.JS
硅谷明星创业公司Vercel的React开发框架,稳定,开发体验好,支持Unbundled Dev, SwC等,其同样有Serverless 一键部署平台帮助开发者快速完成部署。口号是"Let's Make Web Faster”
-
MODERN.JS 字节跳动Web Infra团队研发的全栈开发框架,内置了很多开箱即用的能力与最佳实践,可以减少很多调研选择工具的时间。
-
Blitz 无API思想的全栈开发框架,开发过程中无需写API调用与CRUD逻辑,适合前后端紧密结合的小团队项目。