关于react 的状态管理
关于react 的状态管理
2023-10-22|最后更新: 2024-2-23
type
status
date
slug
summary
tags
category
icon
password
Blocking
Blocked by
top
URL
Sub-item
Parent item

Provider + Context(useContext)

一个完整的例子

context 可以实现基础的状态共享。步骤:
  1. 通过createContext创建一个Context,并设置默认值。
  1. Context 中的值都在 Provider 的作用域下有效。所以在最外层包一个 Provider,value中设置传递值。
  1. 如果子组件需要时,则通过 React.useContext拿到Context值。
缺点:
  1. 重复渲染,性能差
当 Context 中的某个属性发生变化时,所有使用该 Context 的子组件都会被重新渲染,即使某些组件可能并未使用到这个属性。
这种问题有两种解决方法:
  1. React.memo 和 shouldComponentUpdate 这两种方式来解决。
  1. 将一个大型的 Context 拆分成多个小的 Context,可以精细地控制每个 Context 的更新,从而减少整个应用程序的重新渲染次数,提高性能和用户体验。
  1. 数据变更方法难以维护
为了保证数据变更方法的可维护性与 action 的不变性,有两种方法但各有问题:使用自定义 hooks,但为了不会重复渲染,每个修改方法需要使用useCallback,需要声明依赖,会造成极大的心智负担。使用useReducer,不支持异步函数、不支持内部的 reducer 互相调用,不支持和其他 state 联动(比如要当参数传进去才可用)。
  1. 使用范围限制
context的store只能在react中使用,无法在外部函数使用,例如请求函数中需要store中的属性,不能直接在请求函数中调用,就只能通过react中作为参数传递。
  1. 无法处理异步请求。
对于异步的逻辑,Context API并没有提供任何API,需要自己做封装。
  1. 无法处理数据间的联动
Context API并没有提供API来生成派生状态,同样也需要自行去封装一些方法来实现。
 

Redux

Redux 本身是一个 JavaScript 状态容器,提供可预测化状态的管理。社区通常认为 Redux 是 Flux 的一个简化设计版本,但它吸收了 Elm 的架构思想,更像一个混合产物。它提供的状态管理,简化了一些高级特性的实现成本,比如撤销、重做、实时编辑、时间旅行、服务端同构等。
Redux 的核心设计包含了三大原则:
  1. 单一数据源、
  1. 纯函数 Reducer、
  1. 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。
这其实就是一种发布-订阅模式的实现:创建代理对象并监听操作,通过内部机制通知所有依赖这些状态的组件进行更新。
notion image

Zustand

原理

notion image

状态共享

context需要在最外层包一个 Provider。 Context 中的值都在 Provider 的作用域下有效。而 zustand默认是单例模式, 不需要 Provider。直接声明一个 hooks 式的 useStore 后就可以在不同组件中进行调用。
如果需要多实例的话,zustand 也提供了对应的 Provider 的书写方式,

状态变更

  1. 函数可以直接写,完全不用区分同步或者异步。
  1. zustand 会默认将所有的函数保持同一引用。用 zustand 写的方法,默认都不会造成额外的重复渲染。
  1. 更好的状态内聚性,可以互相调用,不用再重新声明函数。

状态派生

  1. zustand 用了类似 redux selector 的方法,实现相应的状态派生。
  1. 可以实现只有监听的属性变化,才会重新渲染

状态组合

可以将相关的状态进行组合,结合中间件实现对单个状态组合进行一些操作,例如对状态组合实现持久化,缓存到localStorage

多环境集成

可以不在 react 环境内直接获取状态数据

引用:
 
 
微前端总结前端错误监控
Loading...