跳到主要内容

谈谈状态管理方案

  • 可以解决组件之间传值,兄弟组件之间通信,多层组件嵌套传值,可以管理复杂应用的数据状态
  • 目的是为了管理共享状态

vue状态管理​

vuex​

  • vuex只有一个store,核心是state、getter、mutation、action、modules,getter相当于store计算属性, mutation处理同步任务,action处理异步任务,mudules可以将store分割成多个模块,解决了vuex只有一个store,会导致所有状态都存储在一个对象,会变得比较复杂,难以维护,mudules就可以解决这个问题

vuex核心​

  • state:存放状态数据的地方,其中数据是响应式的。
  • getter:可理解为store的计算属性,能读取state中的数据。
  • mutations:是改变state中数据的唯一方法,修改数据是同步的。
  • actions:提交mutations修改数据,与mutations功能类似,但修改数据是异步的。
  • modules:当store过于臃肿时,可使用modules将store分割成模块,每个模块中都有自己的state、getter、mutations、actions。

pinia​

你是如何使用pinia

  • 多层组件嵌套通信的、或者全局配置状态的,使用pinia来管理状态

  • 状态发生变化,使用$subscribe来监听状态变化

  • 对于异步接口之间依赖,考虑使用$onAction来监听触发

  • 通过用markRow可以给每一个store注入路由

  • 通过pinia插件,统一给stote添加属性

    • pinia插件就是给每一个store添加属性

pinia和vuex对比​

  • pinia完美支持ts,轻量级
  • pinia支持多个store
  • pinia在vue2中也可以使用,需要安装插件PiniaVuePlugin才能使pinia工作
  • pinia相当于vuex体积更小

pinia为什么没有mutations?​

  • pinia使用action来处理异步和同步方法

为什么vuex只有一个store,pinia有多个store?​

  • pinia多个stote可以更好模块化,减少命名冲突

一个stroe缺点

  • 命名冲突, 在一个大型应用中,如果所有的状态都被集中在一个 store 中,可能会导致命名冲突的问题
  • 复杂性增加, 一个store可能会变得复杂和庞大。在处理大量状态和相关操作时,可能会变得难以维护和理解

多个store的缺点

  • 多个store增加了通信的复杂
  • 多个store增加了内存占用

多个store的好处

  • 模块化
  • 减少命名冲突
  • 每个 store 可以独立更新和计算状态,减少了不必要的依赖和计算。

react状态管理​

redux​

redux的设计思想​

Redux是单一数据源,所有的状态都保存在同一个对象里面,Redux的状态是不可变的,意味着Redux的状态是不可直接修改的,任何对状态的修改都必须通过Reducer返回一个新的状态,更改状态会触发监听函数,触发重新渲染视图

  • Store : 通过Store存储所有的状态,, 是单一数据源。

    • createStore来创建Store
  • Action (dispatch分发action =>目的用于操作state状态)

    • 每一次dispatch分发,都会把Reduces执行
  • Store自动调用Reducer ,并且传入两个参数:当前 State 和收到的Action

  • Reducer 会返回新的 State

    • 在Reducer中,需要浅拷贝state,防止污染state,否则的话 在同一个引用地址操作,会造成污染
  • 每当 dispatch分发action 的时候就会执行subscribe方法,subscribe方法表示订阅状态的变化

redux 优缺点​

优点:

  • redux 所有状态变更都需要 dispath,变得完全可控
  • 可以自定义各种中间件

缺点:

  • redux 需要些很多冗余的代码,如一堆action、reducer

redux 为什么要把 reducer 设计成纯函数​

由于 redux 的状态是不可变的,也就是说,每次状态变化都会产生一个全新的状态对象。如果 reducer 不是纯函数,那么就可能会对状态产生副作用,例如修改原有状态对象的属性值,这样就会破坏状态的不可变性。如果状态对象被修改,那么就会对整个应用程序产生不可预测的行为,因为在一个修改后的状态下,同样的 action 可能会导致不同的结果。

store 里的 state 是一个引用类型,多个组件都可能共享这个 state,如果允许直接在组件中修改这个 state,复杂度会变得更高,定位问题会变得异常困难,因为很难搞清楚到底是哪个组件“搞坏”了数据,而采用纯函数就没有这样的副作用。

  • 设计成纯函数的主要原因是为了保证状态变化的可预测性和可维护性。
  • 可以更容易实现时间旅行,回溯历史状态
  • 为了保证返回的新 state 是确定的, 而不是会因为某些副作用返回不确定值的 state

redux注意的地方​

  • store必须是唯一的,多个store是坚决不允许,只能有一个store空间

  • Reducer必须是纯函数

  • 注意redux的所有操作都将指向内存中的同一个state

  • Reducer获取state时,需要先拷贝state,然后再返回这个新的state

    • 注意这里的拷贝state, 需要用浅拷贝
      • 深拷贝的话,会导致性能问题!深拷贝会复制多层,如果数据有多层引用类型,深拷贝会创建新的对象,对象里面的还有一层引用类型也会产生新的地址,即使里面的引用类型数据没有发生变化,也会重新渲染
      • 写 reducer 更新state时,浅拷贝就够了,千万不要深拷贝!!
    • 否则可能会造成state污染,冲突

mobx​

  • mobx 基于响应式管理状态,在mobx5版本以上,基于了proxy来将对象做响应式的代理
  • mobx会将普通的对象转换为可观察的对象,当可观察对象的属性被修改时,MobX 会自动跟踪依赖变化
  • mobx会精确的收集依赖,用到的属性才会更新,如果用不到就不会更新
  • mobx是可变状态,可以直接修改状态
  • mobx核心autorun、observable、toJS

mobx缺点​

优点:

  • 性能,依赖精确收集,精确更新机制
  • Mobx比较灵活自由、数据结构更加清晰,也便于维护
  • mobx不会计算所有状态值,而是计算那些目前处于observable状态中 (计算当前被使用的状态),当前没有被使用,没有被修改的,则不会重新渲染

缺点:

  • 不兼容IE
  • 过于自由
  • mobx的响应式机制使得状态变化在代码中追踪起来麻烦一点

mobx、redux对比​

mobx相比redux,开发难度低、代码量少、渲染性能好

1、redux将数据保存在单一的store中,mobx将数据保存在分散的多个store中

2、redux需要手动处理变化后的操作;mobx数据变化后自动处理响应的操作

3、redux使用不可变状态,不能直接去修改它,而是应该返回一个新的状态,同时使用纯函数;mobx中的状态是可变的,可以直接对其进行修改

  • 最大的区别就是mobx是可变化的状态,redux是不可变的状态

  • 可变状态不需要一堆reduce,action

  • 可变不需要整体比较,mobx是响应式,单点跟踪

4、mobx只追踪那些在函数执行时被读取的 observable 【 只追踪那些使用过的,被修改的observable】

5、redux是不可变,意味着一旦列表某个数据state发生变化,会导致整个列表都会被重新渲染,一个组件相关数据更新时,即使父组件不需要用到这个组件,父组件还是会重新 render,可能会有效率影响

6、性能能方面: mobx 的响应式能精准的通知依赖做更新,而 redux 只能全局通知,而且 mobx 只是修改同一个对象,不是每次创建新对象,性能会比 redux 更高

zustand​

  • 代码简洁,方便,即可几行即可管理全局状态
  • 使用hooks管理状态
  • 支持状态切片
  • 支持外部来修改状态
  • 提供了 subscribe 订阅,可在组件外监听状态变化,以实现状态依赖
  • 数据持久化,zustand自带中间件,真正的持久化,就是把数据存到localstorage
  • 体积小

zustand 原理​

主要利用了React-Hooks和Context API上下文对象来实现状态管理,通过create 函数创建 store,在组件中,通过useStore来访问这个store, 支持这个状态切片来获取store, 通过观察者模式,store变化了,通过subscribe订阅这个组件的状态变化,借助了React的context, 用来分发store,实现创建多个互不干扰的 store 实例,从而解决context重复渲染的问题

  • 采用的全局的状态管理方案。基于观察者模式

zustand 采用观察者模式,对组件进行订阅更新,

因此不需要在最外层提供一个类似redux的Provider包裹层

  • 不需要额外处理 Context 的重复渲染的问题

    zustand的useStore 借助了React的context, 用来分发store,实现创建多个互不干扰的 store 实例,从而解决context重复渲染的问题

  • zustand 内部会判断状态是否更新,状态更新之后通知组件重新渲染【通过 forceUpdate 对组件重渲染】