vue:状态管理库及其部分原理(Vuex、Pinia)

1、为什么要用状态管理库?

多组件的状态共享问题: 当多个组件需要访问和修改相同的数据时,我们需要在组件之间传递 props或者使用事件总线。当,应用就会变得难以维护和调试。

多组件状态同步问题: 当一个组件修改了状态,其他组件可能无法立即得知该变化。

状态变更的追踪问题: 无法追踪到状态的变化是由何处引起的,使得调试和维护变得困难。

2、Vuex

2.1、核心概念

2.1.1、State:用于存储应用程序的状态数据

当你需要在多个组件之间共享数据时,可以将这些数据放入state中。

例如,保存用户登录状态、购物车中的商品列表等。

可以通过在组件中使用store.state.xxx或计算属性来获取状态数据。

2.1.2、Mutation:用于修改状态的方法,必须是同步函数。

什么时候用? 当你需要修改状态时。让所有的状态变更都经过 mutation可以保证状态的变更是可追踪的。

通常,一个 mutation 对应一个状态变更操作。例如,修改用户登录状态、添加商品到购物车等。

2.1.3、Action:用于处理异步逻辑或提交多个 mutation。

什么时候用? 当你需要处理异步操作(例如发起网络请求)或需要在一个 action 中提交多个 mutation 时。

Action 可以包含任意的异步操作,并可以通过提交 mutation 来修改状态。

例如,获取用户信息的异步请求、添加多个商品到购物车等。

2.1.4、Getter:用于从状态中获取派生数据的方法。

什么时候用? 当你需要根据状态state.xxx计算出一些数据时。

Getter 可以将一些复杂的数据计算逻辑封装起来,并在组件中使用 store.getters 来获取计算后的数据。

例如,基于购物车商品列表计算购物车总价、根据用户权限判断是否具有管理员角色等。

2.2、原理(v4.0.2)

2.2.1、vuex如何挂载到vue实例的

js 复制代码
install (app, injectKey) {
  // 使用`vue.provide()`将`vuex`提供给整个应用
  app.provide(injectKey || storeKey, this)
  // 将vuex实例赋值给vue.$store;
  // 在项目的非setup中可以使用this.$store.state.xxx取值就是这样来的
  app.config.globalProperties.$store = this
}

2.2.2、useStore 源码

js 复制代码
import { inject } from 'vue'

export const storeKey = 'store'

export function useStore (key = null) {
  return inject(key !== null ? key : storeKey)
}

commit源码

typescript 复制代码
  commit (_type, _payload, _options) {
    const { type, payload, options } = unifyObjectStyle(_type, _payload, _options)

    const mutation = { type, payload }
    // 查找该类型对应的 mutations
    const entry = this._mutations[type]
    if (!entry) {
      return
    }
    // 执行mutations对应的处理函数
    this._withCommit(() => {
      entry.forEach(function commitIterator (handler) {
        handler(payload)
      })
    })

    // 通知订阅者
    this._subscribers
      .slice() // shallow copy to prevent iterator invalidation if subscriber synchronously calls unsubscribe
      .forEach(sub => sub(mutation, this.state))
  }

3、Pinia

相比vuex的优势:

  • 可通过devtools追踪数据变化,无需通过commit提交Mutation
  • 支持TS,提供代码自动补全,源码为TS编写;vuex是用JS编写的,vuex要支持TS需要安装插件
  • pinia更轻,大小只有 1kb 左右

改变状态的方法

  • 直接修改变量
  • 调用action
  • 调用patch

3.1原理

install 原理与vuex一致

typescript 复制代码
  	let toBeInstalled: PiniaPlugin[] = []
    install(app: App) {
      if (!isVue2) {
        pinia._a = app
        // 暴露pinia,组件通过inject注入pinia实例
        app.provide(piniaSymbol, pinia)
        // 模版中可通过$pinia访问
        app.config.globalProperties.$pinia = pinia
        // 将pinia的plugin 存到插件列表
        toBeInstalled.forEach((plugin) => _p.push(plugin))
        toBeInstalled = []
      }
    },

pinia的plugin实现原理

1、在调用vue.use(pinia)之前注入插件的情况,会将plugin存放到toBeInstalled列表,

2、调用vue.use(pinia)之后,会将toBeInstalled的插件存到pinia实例的_p中

3、调用useStore时将plugin注入每个Store实例

typescript 复制代码
    pinia.use(plugin) {
      if (!this._a && !isVue2) {
        toBeInstalled.push(plugin)
      } else {
        _p.push(plugin)
      }
      return this
    }
typescript 复制代码
useStore(pinia) {
 if (!pinia._s.has(id)) {
      // creating the store registers it in `pinia._s`
      if (isSetupStore) {
        createSetupStore(id, setup, options, pinia)
      } else {
        createOptionsStore(id, options as any, pinia)
      }

      /* istanbul ignore else */
      if (__DEV__) {
        // @ts-expect-error: not the right inferred type
        useStore._pinia = pinia
      }
    }
}
typescript 复制代码
createSetupStore () {
	pinia._p.forEach((extender) => {
		assign(
        store,
        scope.run(() =>
          extender({
            store: store as Store,
            app: pinia._a,
            pinia,
            options: optionsForPlugin,
          })
        )!
      )
	})
}
相关推荐
To_OC10 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
To_OC10 小时前
LC 17 电话号码的字母组合:我的回溯算法,就是从这道题开窍的
javascript·算法·leetcode
vipbic10 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy10 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志11 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble12 小时前
c端系统,其实更像一个信息展示平台
前端
你怎么知道我是队长12 小时前
JavaScript的变量和数据类型介绍
开发语言·javascript·ecmascript
李姆斯13 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜13 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司14 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能