React初识 | 青训营笔记
这是我参与「第四届青训营 」笔记创作活动的的第9天。
今天这节课收获挺大的,逐层渐进地了解了React的设计思路和基本实现方式,以及现代常见的基于React开发的工程化框架。
初识React
React:是Facebook开发的一款JS库。
“A javascript library for building user interfaces.”
React应用
- 前端应用开发,如Facebook、Instagram、Netflix网页版
- 移动原生应用开发,如Instagram,Discord,Oculus
- 结合Electron,进行桌面应用开发
React设计思路
React设计思路01 —— UI编程的痛点(对症下药)
- 状态更新, UI不会自动更新, 需要手动调用DOM进行更新
- 欠缺基本的代码层面的封装和隔离, 代码层面没有组件化
- UI之间的数据依赖关系, 需要手动维护, 如果依赖链路长, 则会遇到"Callback Hell
React设计思路02 —— 响应式与转换式
前端UI(采用响应式系统):
React设计与实现 —— 响应式编程
- 状态更新, UI自动更新
- 前端代码组件化, 可复用, 可封装
- 状态之间的互相依赖关系, 只需声明即可
React设计与实现01 —— 组件化
ps:
DOM不是JS的变量, DOM本身是浏览器内部维护的状态, 我们只能通过调用JS的DOM-API去修改DOM, 不可以去随意的修改它,
DOM和UI是一一对应的关系
总结:
- 组件是组件的组合/原子组件
- 组件内拥有状态, 外部不可见
- 父组件可将状态传入组件内部
React的设计与实现02 —— 状态归属问题
上图中,当前价格 状态属于谁?
当前价格属于Root节点
状态归属于两个节点向上寻找到最近的祖宗节点。
即:当多个组件需要共享同一个数据时,这个数据存在的位置应该位于所有共享组件的父节点以上。
当前价格如何改变?
提示:在js中,函数是一等公民,也就是说可以将函数看作一个变量
将onChangeValue()向下传递
React是单向数据流, 还是双向数据流?)
React是单向数据流。
- 永远是父组件给子组件传东西(函数/变量),
- 子组件不能给父组件传东西, 子组件不能改变父组件的状态,
- 子组件只能通过接受父组件传递过来的函数, 进而改变父组件的状态
如何解决状态不合理上升的问题?
在状态管理库中实现
React的设计与实现03 —— 组件化
组件设计:
- 组件声明了状态和UI的映射
- 组件有Props/State两种状态
- "组件"可以由其他组件拼装而成
组件代码会是什么样子?
- 组件内部拥有私有状态State
- 组件接受外部的Porps状态提供复用性
- 根据当前的State/Props, 返回一个UI
React的设计与实现04 —— 生命周期
组件的生命周期可分成三个状态:
- Mounting(挂载):已插入真实 DOM
- Updating(更新):正在被重新渲染
- Unmounting(卸载):已移出真实 DOM
这部分可以看一下菜鸟教程
React(hooks)写法
useState
hooks写法不是直接修改变量,而是通过函数修改变量,实现控制
import {useState} from 'react'
const [count,setCount] = useState(0)
//此时修改count就需要调用setCount函数
setCount(count + 1)
hooks提供的工具
- useState ----> 相当于类组件中的 constructor 对数据做初始化
- useEffect----> 对数据进行挂载,更新。在useEffect的 return()=>{ } 中会执行卸载。
- useReducer()可以去了解一下,三个参数。一般可用useState()实现相同效果
- useMemo() 函数值返回依赖,值改变会重新计算。
- useRef 定一个不用渲染页面的值 const searchParmas = useRef(null)
- useContext 定义在父组件中,接收context对象,返回对象当前值,在父组件发生变化时,重新渲染子组件。
- 自定义hooks, 需要使用‘use’开头。
这部分可以看一下这篇文章
「React 进阶」 React 全部 Hooks 使用大全 (包含 React v18 版本 ) - 掘金 (juejin.cn)
React的实现
React的实现 —— Problems
- JSX不符合JS标准语法
- 返回的JSX发生改变时, 如何更新DOM
- State/Props更新时, 要重新触发render函数
1.JSX不符合JS标准语法
解决办法是:transpile(转义)
补充:compile和transpile的区别:
compile是编译, transpile是转义:把一个语法的语言转成另外一个语言(例如less转成css)
HTML本质上是一个树状结构, 每一个节点可以有自己的属性, 可以表示成JSON数据格式, 因此可以转义
2. 返回的JSX发生改变时, 如何更新DOM
真实DOM是浏览器内部维护的状态, 我们只能通过DOM接口去修改DOM, 而不能直接拿到DOM就随便更改
-
指令式编程(面向过程)
- 一步一步, 手动告诉程序怎么做
-
声明式编程(面向对象)
-
发出一个指令, 就把事情办完了;
-
现在主流的前端框架都是声明式编程
-
为什么不把声明式编程的方式植入浏览器中?
- 浏览器作为应用平台, 不能提供更高层次的东西, 这样会把自由度降低
-
-
响应式编程
- 是声明式编程的一种, 当一个事物状态改变时, 改变其他事物的状态
Virtual DOM (虚拟DOM)
Virtual DOM是一种用于和真实DOM同步, 而在JS内存中维护的一个对象, 它具有和DOM类似的树状结构, 并和DOM可以建立一一对应的关系.
它赋予了React声明式的API, 您告诉React希望让UI是什么状态, React就确保DOM匹配该状态. 使您可以从属性操作,事件处理和手动更新DOM这些在构建应用程序时必要的操作中解放出来
React弊病: 当父组件发生状态改变时, 它的所有子节点要全部更新 11
How to Diff?
完美的最小Diff算法, 需要O(n*3)的复杂度
权衡更新次数少和计算速度快的要求, 实际我们牺牲了理论最小Diff, 换取时间, 得到了O(n)复杂度的算法
即Heuristic O(n) Algorithm(启发式O(n)算法)
react状态管理库
React状态管理库将state(状态)抽离到组件外部,进行统一管理。
常见的状态管理库:redux、xstate、mobx、recoil
状态机
当前状态,收到外部事件,迁移到下一个状态。
应用级框架科普
参考博客:
链接:juejin.cn/post/712904…,作者:Luminous