关于react 的状态管理
type
status
date
slug
summary
tags
category
icon
password
Blocking
Blocked by
top
URL
Sub-item
Parent item
Provider + Context(useContext)
一个完整的例子
context 可以实现基础的状态共享。步骤:
- 通过createContext创建一个Context,并设置默认值。
- Context 中的值都在 Provider 的作用域下有效。所以在最外层包一个 Provider,value中设置传递值。
- 如果子组件需要时,则通过 React.useContext拿到Context值。
缺点:
- 重复渲染,性能差
当 Context 中的某个属性发生变化时,所有使用该 Context 的子组件都会被重新渲染,即使某些组件可能并未使用到这个属性。
这种问题有两种解决方法:
- React.memo 和 shouldComponentUpdate 这两种方式来解决。
- 将一个大型的 Context 拆分成多个小的 Context,可以精细地控制每个 Context 的更新,从而减少整个应用程序的重新渲染次数,提高性能和用户体验。
- 数据变更方法难以维护
为了保证数据变更方法的可维护性与 action 的不变性,有两种方法但各有问题:使用自定义 hooks,但为了不会重复渲染,每个修改方法需要使用useCallback,需要声明依赖,会造成极大的心智负担。使用useReducer,不支持异步函数、不支持内部的 reducer 互相调用,不支持和其他 state 联动(比如要当参数传进去才可用)。
- 使用范围限制
context的store只能在react中使用,无法在外部函数使用,例如请求函数中需要store中的属性,不能直接在请求函数中调用,就只能通过react中作为参数传递。
- 无法处理异步请求。
对于异步的逻辑,Context API并没有提供任何API,需要自己做封装。
- 无法处理数据间的联动
Context API并没有提供API来生成派生状态,同样也需要自行去封装一些方法来实现。
Redux
Redux 本身是一个 JavaScript 状态容器,提供可预测化状态的管理。社区通常认为 Redux 是 Flux 的一个简化设计版本,但它吸收了 Elm 的架构思想,更像一个混合产物。它提供的状态管理,简化了一些高级特性的实现成本,比如撤销、重做、实时编辑、时间旅行、服务端同构等。
Redux 的核心设计包含了三大原则:
- 单一数据源、
- 纯函数 Reducer、
- State 是只读的。
redux流程
- 用户(通过view)发出Action,发出方式是调用dispatch方法;
- Store自动调用 Reducer ,传入两个参数,当前state,收到的Action,Reducer 返回新的 State
- state更新后,store就会调用监听函数, 根据state触发重新渲染,更新view
整个流程中数据都是单向流动的,这种方式保证了流程的清晰
核心概念:
- Store :数据中心,整个应用只能有一个store
- State: store对象包含的所有数据
- Action: 用户触发的行为名称(通过action再去触发state的改变,最终响应view的改变)
- Action Creator: 生成action的函数,可生成多种action
- Reducer: store收到action后,处理state的函数,叫到reducer,接收两个参数:action ,和当前state;返回值: 新的state
- Dispatch: view发出action的唯一方法
Mobx
Mobx 通过监听数据的属性变化,可以直接在数据上更改触发UI 的渲染。在使用上更接近 Vue,比起 Flux 与 Redux 的手动挡的体验,更像开自动挡的汽车。Mobx 的响应式实现原理与 Vue 相同,以 Mobx 5 为分界点,5 以前采用 Object.defineProperty 的方案,5 及以后使用 Proxy 的方案。它的优点是样板代码少、简单粗暴、用户学习快、响应式自动更新数据让开发者的心智负担更低。
Redux与 MobX的区别?
【代码量】redux>mobx
- redux: 需要定义一堆的action, dispatch,reducer
- mobx: store和改变的方法
【开发难度】redux>mobx
- mobx:使用面向对象的编程思维,相对简单
- redux:比较复杂,函数式编程思维,同时需要借助一系列的中间件来处理异步和副使用。
【调试难度】mobx>redux
- redux:状态不可变,返回一个新的状态,同时使用纯函数;redux 提供时间回溯的开发工具,同时纯函数以及更少的抽象,让调试变得更加容易
- mobx:中状态可变,可对其直接修改,mobx中有更多的抽象和封装,调试比较困难,同时结果难预测。
【store数】
- redux:单个store。
- mobx:多个store。
【功能性】redux> mobx
- redux: 可回溯状态,时间旅行,适合:画板应用,表格应用,很多时候需要撤销,重做等操作。
- mobx: 直接修改源数据。
适用场景总结:
- mobx: 简单项目,适合数据不复杂的应用
- redux:大型项目,有回溯需求
valtio
类似于mobx。
原理
altio 的实现主要依赖两个核心方法:proxy 和 useSnapshot。
proxy 用于包装原始对象(initialObject),生成一个可监听修改操作的 proxy state。
在组件中,使用 useSnapshot来获取这个proxy state,并返回一个不可变的snapshot。这个snapshot用于组件渲染,当状态需要变更时,我们可以操作proxy state 获取新的 snapshot,触发组件 rerender。
这其实就是一种发布-订阅模式的实现:创建代理对象并监听操作,通过内部机制通知所有依赖这些状态的组件进行更新。

Zustand
原理

状态共享
context需要在最外层包一个 Provider。 Context 中的值都在 Provider 的作用域下有效。而 zustand默认是单例模式, 不需要 Provider。直接声明一个 hooks 式的 useStore 后就可以在不同组件中进行调用。
如果需要多实例的话,zustand 也提供了对应的 Provider 的书写方式,
状态变更
- 函数可以直接写,完全不用区分同步或者异步。
- zustand 会默认将所有的函数保持同一引用。用 zustand 写的方法,默认都不会造成额外的重复渲染。
- 更好的状态内聚性,可以互相调用,不用再重新声明函数。
状态派生
- zustand 用了类似 redux selector 的方法,实现相应的状态派生。
- 可以实现只有监听的属性变化,才会重新渲染
状态组合
可以将相关的状态进行组合,结合中间件实现对单个状态组合进行一些操作,例如对状态组合实现持久化,缓存到localStorage
多环境集成
可以不在 react 环境内直接获取状态数据
引用: