什么是状态管理
为什么需要状态管理
从React诞生之后,前端组件化的方案深入人心,React遵循的是单向数据流的原则,属性通过Props自上而下的传递。当页面的比较简单,组件之间的层级关系比较浅时,这种自上而下的单向数据流的方式是不会有问题的。如果页面一复杂,组件的嵌套层级一深,这种单向数据流的传递方式,将会使你陷入到“嵌套地狱”
状态管理本身,解决的就是这种“嵌套”地狱的问题,解决跨层级组件之间的数据通信和状态共享
状态管理工具
状态管理工具的本质:管理共享内存中的状态
- 共享内存
- 管理状态
- 页面通信
- 组件通信
- 刷新失效?
详细定义:单页应用的各个组件本身是共享内存的,如果将状态保存在内存中就可以读写统一内存中的变量, 从而达到状态共享的目的。
React状态管理工具简介
React状态管理工具可以分为以下几类:
- React自带: Local State(props)和Context
- 单向数据流: Flux、Redux(Redux-toolkit)
- 双向数据绑定:Mobx
- 原子型状态管理: Recoil、Jotai
- 异步操作密集型:Rxis
每一种状态管理工具都有其不同的适用性,不同场景下需要合理的选择状态管理工具。
Local State(props)
local State顾名思义,就是组件级别的局部状态,比如:
import {useState] from 'react'
const Hello = ()=> {
const [name,setName] = useState('Jony')
return <>Hello,name]</>
}
上述的name就是一个最简单的局部local State。只在Hello这个组件中生效,当组件创建时初始化和生效,组件销毁时失效。
Context
React中的Context解决了react中,props或者state进行多级数据传递,则数据需要自顶下流经过每一级组件,无法跨级的问题。
但是Context在页面间共享数据的时候同样有很多问题
- Context相当于全局变量,难以追溯数据的变更情况
- 使用Context的组件内部耦合度太高,不利于组件的复用和单元测试
- 会产生不必要的更新(比如会穿透memo和dependicies等)
- Context只能存储单一值,无法存储多个各自拥有消费者的值的集合
- 粒度也不太好控制,不能细粒度的区分组件依赖了哪一个Context
- 多个Context会存在层层嵌套的问题
Redux
Redux的三大原则: 单一数据源,只有一个store、store中的state是只读的、使用纯函数来执行修改
- 单一数据源:
在redux中,整个应用的全局State(再次注意是全局state),都会保存在一个store中,一个单一数据源 state tree 也简化了应用的调试和和监控;它也让你在开发中能将应用数据持久化到本地,从而加速开发周期。此外,有一些功能以前很难实现,比如“撤销/重做”,在单一数据源的原则下,使用 Redux 实现将非常容易 - Store中的State是只读的:
我们不能直接修改store中的state, store中的state是只读的。唯一能改变store中的state的方式就是通过action - 使用纯函数来执行修改:
接受纯函数来接受aciton,该纯函数叫reducer,可以改变store中的state
Redux特点
因为Redux的上述特性,使得Redux可以做时间旅行。时间旅行: 顾名思义,就是可以随时穿越到以前和未来让应用程序切换到任意时间的状态。因此,如果复杂的场景,特别是存在页面组件间复杂的通信的场景非常适合用Redux来管理状态
Redux 比较适合用于大型 Web 项目,尤其是一些交互足够复杂、组件通信频繁的场景,状态可预测和回溯是非常有价值的。还有一种场景,比如需要事故重现,这种定义和上报事故异常和重现的场景,Redux也很有意义。