【青训营】响应式系统与React

142 阅读6分钟

这是我参与2022首次更文挑战的第11天,活动详情查看:2022首次更文挑战

授课老师:露脸的牛岱老师

React 前置知识

  1. HTML,CSS,JS基础。
  2. 基础的数据结构/算法知识,如二叉树,深度遍历等。
  3. 会适用浏览器提供的DOM API来修改DOM,更新UI。

内容概要

  1. React的历史与应用
  2. React的设计思路
  3. React (hooks) 的写法
  4. React的实现
  5. React状态管理库
  6. 应用级框架科普

01.React 历史与应用

历史

  1. 启发: 10年facebook引入的php框架 xhp,这种组合式组件思想是React的启发。
  2. 原型: 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
  1. 开源:Jordan Walke开源React。
  2. 生态大爆发: 2014 - 至今。各种围绕React的新工具/新框架开始涌现。

image.png

应用

热知识:字节大部分前端体系都是React🤡

  1. 前端应用开发,如Facebook,Instagram,Netflix网页版。
  2. 移动原生应用开发,如Instagram,Discord,Oculus。
  3. 结合Electron,进行桌面应用开发。

React swiper 3D图形库

02.React的设计思路

推演React的设计思路

问题:通过选择各种选项,通过回调修改变量currentValue。但是还需要通过DOM去重新渲染当前价格。

image.png

总结:UI编程痛点。

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

响应式与转化式

转换式系统和响应式系统一样吗? image.png

转换式系统:我们学的编译原理,算法,抽象起来都可以说转换式系统的体现,这是一种给定输入,求解输出的过程

响应式系统:类似于监控系统和上述的UI界面,我们更加关注的是如何监听事件以及监听事件后如何进行消息驱动,即当事件发生后需要做什么。

响应式系统的执行流程:

graph TD
事件 --> 执行既定的回调 --> 状态变更

对应到我们所说的前端UI界面,只需要在状态变更后额外增加UI更新的步骤即可。

graph TD
事件 --> 执行既定的回调 --> 状态变更 --> UI更新

响应式编程

响应式编程有哪些特点?

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

怎么理解这里的“声明”:比如我需要a永远等于b+c,那么,当b或者c任何一个变量改变时,a变量会自动更新。不需要我去额外调用一个函数来更新a的值。

组件化

接回之前说过的UI问题。我们可以给手机界面划分成一个个组件,其中组件可以嵌套子组件:

image.png

graph TD
root --> 内容 --> 配置面板 --> 型号选择 --> iPhone13
root  --> 顶栏
内容 --> 橱窗
配置面板 --> 颜色选择
型号选择 --> iPhone13_Pro
颜色选择 --> 红
颜色选择 --> 橙

注意:上面不是一棵DOM树,只是为了清晰地区分组件,进行的人为划分。

总结:

  1. 组件是组件的组合/原子组件
  2. 组件内拥有状态,外部不可见
  3. 父组件可将状态传入组件内部

状态归属问题

问题: 当前价格应该属于哪一个节点?

答: Root,所有的子组件需要共享的数据都需要放置在父组件中。

问题:如果所有的子组件的数据都给父组件管理,可以吗???

答:尽可能保证局部性。(状态上升)状态归属于两个节点向上寻找的最近公共祖先。

问题:在子组件中修改对应选项,如何在Root中修改当前价格?

答:向子组件传递函数,在子组件的选择上触发回调,调用传递的函数。

思考

  1. React是单向数据流,还是双向数据流?

只能父传子,所以是单向数据流。

  1. 如何解决状态不合理上升的问题?

通过状态管理库来解决该问题。

  1. 组件的状态改变后,如何更新DOM?

这里需要使用一些DOM更新算法(DIFF)来判断并对对应的DOM进行更新。

组件化设计

所以,为了解决UI痛点,我们的组件需要设计成什么样子?

  1. 组件声明了状态和UI的映射。

  2. 组件有Props/ State两种状态。

  3. “组件”可由其他组件拼装而成。

那么,对应的组件代码是什么样子?

  1. 组件内部拥有私有状态State。
  2. 组件接受外部的Props状态提供复用性。
  3. 根据当前的State/ Props,返回一个UI。

(下面是老师给出的想象,并非是react的语法。)

image.png

组件的生命周期

React组件的生命周期主要有三个时间点:挂载Mounting更新Updating卸载Unmounting

image.png

03. React (hooks)的写法

代码1:封装更新

image.png

代码2:副作用(网络请求,影响外部,使用useEffect())

image.png

hook使用法则

  1. 不要在循环,条件或嵌套中使用hook

image.png

04.React的实现

Problems

  1. JSX不符合JS标准语法。
  2. 返回的JSX发生改变时,如何更新DOM?
  3. State/Prop更新时,如何重新触发render?

针对第一个问题: JSX语法的本质:还是以 React.createElement 的形式来实现的,并没有直接把用户写的HTML代码,渲染到页面上;

image.png

第二个问题:

Virtual DOM (虚拟DOM) Virtual DOM是一种用于和真实DOM同步,而在JS内存中维护的一个对象,它具有和DO M类似的树状结构,并和DOM 可以建立一一 对应的关系。 它赋予了React声明式的API:您告诉React希望让UI是什么状态,React 就确保D OM匹配该状态。这使您可以从属性操作、事件处理和手动D OM更新这些在构建应用程序时必要的操作中解放出来。

真实的DOM不是JS的对象。我们是通过操作DOM的接口来更新DOM的。

声明式编程 / 指令式 / 响应式编程的区别?

浏览器需要更高层的抽象。

image.png

父组件下的所有子组件都需要更新。

image.png

完美的最小Diff算法,需要O(n^3)的复杂度。 牺牲理论最小Diff,换取时间,得到了0 (n)复杂度的算法:启发式算法。 Heuristic O(n) Algorithm

类型不同替换--属性不同更新--存在子组件递归

05.React状态管理库

核心思想:将状态抽离到UI外部进行统一管理。

降低组件的复用性,强耦合。

image.png

redux:用得多,但是最近设计有些问题。

const [{x,y},{incrementX,incrementY}] = UseModel(countModel);

06. 应用级框架科普

  1. NEXT.JS

硅谷明星创业公司Vercel的React开发框架,稳定,开发体验好,支持Unbundled Dev, SwC等,其同样有Serverless 一键部署平台帮助开发者快速完成部署。口号是"Let's Make Web Faster”

  1. MODERN.JS 字节跳动Web Infra团队研发的全栈开发框架,内置了很多开箱即用的能力与最佳实践,可以减少很多调研选择工具的时间。

  2. Blitz 无API思想的全栈开发框架,开发过程中无需写API调用与CRUD逻辑,适合前后端紧密结合的小团队项目。