这是我参与「第四届青训营 」笔记创作活动的的第7天
历史与应用
-
2010年,FaceBook在其php生态中,引入了xhp框架,首次引入了组合式组件的思想,启发了后来的React的设计。
-
Jordan Walke创造了FaxJS,也就是后来的React原型
-
2012年,FaceBook收购Instagram后,该FaxJS项目在内部得到使用,Jordan Walke基于此经验,创造了React。
-
2013年,React正式开源,在2013JSConf上其介绍了这款框架。
-
2014年-今天:各种新工具/框架。
设计思路
UI编程痛点
- 状态更新,UI不会自动更新,需要手动地调用DOM进行更新。
- 欠缺基本的代码层面的封装和隔离,代码层面没有组件化。
- UI之间的数据依赖关系,需要手动维护。如果依赖链路长,则会遇到callback hell。
响应式与转换式
-
转换式系统:给定输入,求解输出
- 编译器
- 数值计算
-
响应式系统:监听事件,消息驱动
- 监控系统
- UI 界面
响应式系统
前端 UI:
响应式编程
- 状态更新,UI自动更新。
- 前端代码组件化,可复用、可封装(避免出现屎山)。
- 状态之间互相依赖关系,只需要声明即可。
React 哲学
你可以自上而下或者自下而上构建应用:
自上而下意味着首先编写层级较高的组件,自下而上意味着从最基本的组件开始编写。
当你的应用比较简单时,使用自上而下的方式更方便;对于较为大型的项目来说,自下而上地构建,并同时为低层组件编写测试是更加简单的方式。
只保留应用所需的可变 state 的最小集合,其他数据均由它们计算产生
通过问自己以下三个问题,你可以逐个检查相应数据是否属于 state:
- 该数据是否是由父组件通过 props 传递而来的?如果是,那它应该不是 state。
- 该数据是否随时间的推移而保持不变?如果是,那它应该也不是 state。
- 你能否根据其他 state 或 props 计算出该数据的值?如果是,那它也不是 state。
组件化
- 组件是 组件的组合 / 原子组件。
- 组件内拥有状态,外部不可见。
- 父组件可以将状态传入组件内部。(让父组件能够控制子组件)
状态归属问题?
如果多个同级组件要共同管理一个状态,就会发生“状态上升”的情况。
状态上升:状态归属于两个节点向上寻找到的最近的祖宗节点。
当有大量状态上升到Root节点,就会导致状态管理混乱。此时需要引入全局状态管理的概念。
Q1:React是单向数据流,还是双向数据流?
单向数据流。 React仅支持父组件向子组件传值。
子组件想要修改父组件的值,需要父组件向子组件提供修改父组件本身属性的方法(函数在JS中是一等公民)
Q2:如何解决状态不合理上升的问题?
状态管理库。
Q3:组件的状态改变后,如何更新DOM?
Virtual DOM + Diff算法。
组件设计
- 组件声明了状态和UI的映射。
- 组件有Props / State 两种状态。
- 组件可由其他组件拼装而成。
生命周期
声明周期在纵向上分为三个状态:
- Mounting
- Updating
- Unmounting
hooks的写法
函数副作用
函数副作用是指函数在正常工作任务之外对外部环境所施加的影响。
具体地说,函数副作用是指函数被调用,完成了函数既定的计算任务,但同时因为访问了外部数据,尤其是因为对外部数据进行了写操作,从而一定程度地改变了系统环境。函数的副作用也有可能是发生在函数运行期间,由于对外部数据的改变,导致了同步运行的外部函数受到影响。
useEffect
传入一个函数和一个数组,数组是状态的数组,称为依赖项。该函数在mount、依赖项被set时执行。
有副作用的函数,要传进useEffect中执行。
不要在循环、条件或嵌套函数中调用Hooks。
源码实现
JSX不符合JS标准:转译
返回的JSX改变时,如何更新DOM?
Virtual DOM(虚拟DOM)?
Virtual DOM是一种用于和真实DOM同步,而在JS内存中维护的一个对象,它具有和DOM类似的树状结构,并和DOM可以建立一一对应的关系。
不同编程范式
- 指定式编程?(关注过程,C/C++)
- 声明式编程?(函数式编程,关注要做的事)
- 响应式编程?
State / Props更新时,要重新触发render函数
How to diff?
| 元素 | 操作 |
|---|---|
| 不同类型的元素 | 替换 |
| 同类型的DOM元素 | 更新 |
| 同类型的组件元素 | 递归 |
状态管理库
将状态抽离到UI外部进行统一管理。
何时使用:当前状态是否是整个App共同拥有的?
状态机
它是一个有向图形,由一组节点和一组相应的转移函数组成。状态机通过响应一系列事件而“运行”。每个事件都在属于“当前” 节点的转移函数的控制范围内,其中函数的范围是节点的一个子集。函数返回“下一个”(也许是同一个)节点。这些节点中至少有一个必须是终态。当到达终态, 状态机停止。
应用级框架科普
-
Next.js:支持Unbundled Dev、SWC等,拥有Serverless一键部署
-
Modern.js:全栈开发框架,内置许多开箱即用的工具。
-
Blitz:无API思想的全栈开发框架,开发过程中无需写API调用和CRUD逻辑,适合前后端紧密结合的小团队项目。
课后问题
1. React 组件的 render 函数,在哪些时机下,会被重新执行?
组件中的state和props发生改变时。
2. React这种函数式编程,和 vue这种基于模版语法的前端框架,各有什么优点和缺点?
Vue.js
- 性能好:使用官方提供的模板语法的组件不需要考虑性能优化。
- 适应性:代码结构类似HTML、CSS、JS,无障碍迁移。
- 灵活度低:相比React函数式的写法,灵活度不足。
React.js
- 需要手动优化性能,对初学者不友好。
- 灵活度高:依靠jsx这种函数式写法,能够使页面的编写像写js代码一样灵活。
- 学习成本低:这里的成本指的是不需要记忆vue的那些模板写法(例如v-if、v-for等)。
3. React 推荐使用组合来进行组件的复用,而不是继承,背后有什么样的考虑?
因为本人并未使用过Rect,对于此没有深刻概念。知乎对此问题珠玉在前,在此贴出链接,仅供参考: