React库和框架的区别是什么?
- 页面组件化
- 数据驱动
MVC V层
react库
react.js是一个开放的js工具库,用于基于UI自检构建用户界面
react框架
通过脚手架工具搭建的一套完善的前端环境,包括:路由、状态管理、数据获取、第三方的UI组件库和第三方Hooks库(ahooks react-use)
严格模式
检查组件是否为纯函数
及早的发现useEffect中的错误
警告过时的API
ESLint
代码规范插件
npm run lint
vite-plugin-eslint (vite构建下)
Prettier
代码格式化插件
react模块
核心功能
组件
react-dom
操作浏览器DOM
react-dom/client
客户端渲染使用
react-dom/server
服务端渲染使用
分离不同代码库,可跨平台使用
比如 编写
react-native
应用,当然不用使用react-dom
模块
利用编译器编译成中间这种reactElement
对象格式(虚拟DOM),再利用react-dom
库完成
fragment
<></>
简写,这种方式不能写key
classnames 控制样式
事件
合成事件:处理事件有差异(onmouseenter 实际使用的是over)
事件委托:委托到容器’root’元素
传参处理
箭头函数
高阶函数
条件渲染
条件分支if else switch case
三目 ? :
逻辑运算符 || ?? &&
不会渲染的值:null、undefined、boolean、‘’ 、对象、函数
利用JSON.stringify() 或者 {undefied +‘’}(拼接空串)
数组渲染
jsx默认对数组进行join()操作
循环语句
数组方法(map)
必须写key
帮助react推断发生了什么,从而得以正确的更新DOM树
跟踪列表每一项的身份, 唯一标识
组件的点标记写法
对象形式
组件写为对象的方法
可解构使用
函数形式(更好的进行组件分类
将组件直接挂载在上级组件上
组件通信方式
props传递值
整体接收, 解构接收
props传递事件
通过扩展运算符{…}批量上传
组件组合方式
插槽
利用props的children属性
指定顺序
props默认值
利用es6的默认值方式
react的defaultProps
props类型限定
使用ts
使用第三方proptypes
组件纯函数
只负责自己的任务,不会在更改函数调用前就已存在的对象和变量。(不能修改这个函数组件作用域外的对象和变量)
严格模式检测当前组件是否为纯函数,对这函数调用两次,检测值是否变化
输入相同,则输出相同。纯函数总是返回相同的结果。
不管调用多次,函数都输出同一个值,对于测试更方便。增强健壮性
组件的状态
瞬间变化的数据被称为状态(state),状态可以进行数据驱动
useState hooks 提供 状态 和 修改状态的方法
普通变量 无法重新渲染JSX
state状态,重新触发函数组件,并且具备组件的记忆。
普通纯函数函数, 多次调用执行结果
状态是如何改变视图的
渲染与提交的过程
1️⃣触发一次渲染
💡组件的初次渲染,createRoot.render
🔦内部状态更新,触发渲染送入队列
2️⃣渲染您的组件
💡在进行初次渲染,react调用根组件<App/>
🔦内部状态更新,会渲染对应的函数组件
3️⃣提交到DOM上
💡初次渲染,appendChild DOM API
🔦内部状态更新,更新差异的DOM节点
多状态如何正确记忆?
同一个组件的每次渲染中,useState都依托于一个稳定的调用顺序
在react内部,每个组件保存了一个数组, 按照索引记忆usestate位置。[{索引,useState对}]
所以不要将useState写到一些分支逻辑中,会打乱useState顺序
配合eslint检查,语法是否合规
状态的快照
本次作用域中的状态不会改变
点击后,触发三次setcount,但是当前作用域的count都为0
快照的陷阱,异步的时候造成错觉,其实异步逻辑中的状态还是依赖于这次函数作用域
词法作用域,只看定义,不看调用
状态队列与自动批处理
自动批处理
等事件处理函数中的所有代码都运行完毕再处理你的state更新
队列都执行完毕后,在进行ui更新
更新函数的写法
形参c来自于react内部,所以这里并不是保存的count快照,连续调用三次后,得到3
更新函数在内部还是以回调的形式,但没使用形参
严格遵守状态不可变
默认情况下,修改的状态跟上一次相同的情况下,是不会重新触发渲染
引用数据类型
拷贝
数组,使用相关方法
扩展运算符
深克隆(将没改变的数据也是克隆了一份)
immer useimmer 可以直接对数据进行修改
惰性初始化状态的值
当状态的值组要通过复杂计算才能得到的话,可以对其进行惰性初始化
只在初始化的时候执行一次
状态提升解决共享问题
父组件管理状态,子组件props
状态的重置处理问题
当组件被销毁会时,所对应的状态也会被重置
当组件位置没有发生变化,状态会被保留
组件渲染位置发生变化,状态不被保留
不同的结构体,给组件添加key属性
diff算法,同层级的元素是否发生改变
利用状态产生计算变量
根据状态会重新渲染组件的特性,利用当前状态快照生成对应的计算变量
受控组件与非受控组件
通过props控制的组件成为受控,通过state控制的组件称为非受控组件
react表单内置了受控组件的行为
value + onChange
checked + onChange
input标签并不是原始的标签
1 | const App = () => { |
Hooks
react中以use开头的函数被称为Hook钩子,Hooks被称为use函数的集合,也就是钩子的集合
Hooks就是一堆功能函数,(像插件
分为: 内置、自定义、第三方
useRef
使用ref引用一个值,具备记忆功能
改变ref不会触发重新渲染组件
定时器案例:timer用ref存储,始终引用的同一个值
useref进行dom操作
如:让元素获取焦点,滚动到他或测量尺寸位置
回调写法,在逻辑中操作dom
forwardRef
给组件设置ref需要forwardRef转发
forwardRef让您的组件通过ref向父组件公开DOM节点
直接转发ref给子组件报错
useImperativeHandle
自定义由ref暴露出来的句柄
纯函数处理useEffect
纯函数:
副作用:
函数在执行过程中对外部造成的影响成为副作用,如ajax、dom操作、与外部系统同步
事件可以处理副作用,onclick事件等
处理副作用,借助useEffect钩子
useEffect触发时机,jsx渲染后触发
依赖项,内部通过Object.is() 方法判定
当依赖项为空,指挥初始渲染
ESLint会检查依赖项是否正确,包括props state 计算变量
函数写在useEffect中
useCallback
函数始终是同一个
每次重新渲染函数,函数指向地址发生改变
useEffect清理工作
严格模式,检测有无做清理工作
初始化数据时,注意清理操作,
更简洁的方法是使用第三方,ahooks的useRequest
useEffectEvent
useLayoutEffect 同步执行状态更新
useEffect是在渲染之后,更新之前
如过需要在useEffect中处理DOM,并且改变页面的样式,就需要使用useLayoutEffect,
useInsertionEffect DOM更新前触发
此时拿不到dom元素
在css-in-js库中使用的多
useReducer
局部的状态管理,抽离逻辑
useImmerReducer
immer类型数据
Context向组件深层次传递数据
reducer配合context实现状态数据共享
更复杂的情况使用第三方库,redux mobx,zuster
memo在props不变时跳过重新渲染
达到一些性能优化
props改变的情况下,会重新渲染组件
没有props
useMemo对计算结果进行缓存
虽然使用memo,并且props 数组list****值未变化,但是list的引用地址发生变化,底层使用Object.is([], []) ==>flase
比较,则props值改变
使用useMemo对计算数据进行缓存(类似useCallback缓存函数)
useCallback对函数进行缓存
useMemo的一种特殊写法
1 | const fn = useMemo(()=> () => { console.log(1) }) |
StartTrasition 方法及并发模式
react18开始,渲染是一个单一的、不间断的、同步的事务,一旦渲染开始,就不能被中断
react18引入并发模式,允许标记更新作为一个transition,这回告诉react它们可以被中断执行。这样可以把紧急的任务先更新,不紧急的任务后更新
任务切换
useTrasition hook
提供一个pending状态的布尔值,(配合实现一个loading效果),还有一个startTrasition方法
useDeferredValue 延迟
获取该值的延迟版本
useId 产生唯一标识
id 局部前缀
xxx + id (字符串拼接)
id 全局前缀
createRoot 第二参
1 | ReactDOM.createRoot(document.getElementById('root')!, { |
useDebugValue
在自定义hook中打印信息,devtool
useSyncExternalStore
操作状态
订阅外部 store 的 React Hook。