深海鱼的博客 深海鱼的博客
首页
  • 《ES6 教程》
  • 《TypeScript》
  • 《Vue》
  • 《React》
  • 《Git》
  • Javascript
  • CSS
手写系列
  • React项目实战
  • Vue3项目实战
  • 服务端项目实战
  • 鸿蒙项目实战
  • 小小实践
  • Vue全家桶

    • Vue2.0
    • Vue3.0
    • VueRouter
    • Vuex
  • React

    • React
  • Axios
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

深海鱼

尽人事,知天命,知行合一。
首页
  • 《ES6 教程》
  • 《TypeScript》
  • 《Vue》
  • 《React》
  • 《Git》
  • Javascript
  • CSS
手写系列
  • React项目实战
  • Vue3项目实战
  • 服务端项目实战
  • 鸿蒙项目实战
  • 小小实践
  • Vue全家桶

    • Vue2.0
    • Vue3.0
    • VueRouter
    • Vuex
  • React

    • React
  • Axios
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 导读
  • vue2

  • vuex

    • 前言
    • 调式环境准备
    • 源码基本结构与install函数
    • ModuleCollection与Module类
    • Store实例化
    • Store实例方法
    • 辅助函数
    • 内置插件
    • 总结与常见问题
      • 一、总结
        • 1. Vuex是一个Vue插件
        • 2. Store实例
        • 3. 辅助方法
        • 4. 插件系统
      • 二、常见问题
        • 1. 如果在mutation中执行异步操作会怎么样?
        • 2. 如果不使用mutation直接修改state会怎样?
        • 3. 辅助函数是如何通过命名空间查找到对应模块的state、getters、mutation和action的?
  • vue-router

  • vue3

  • react

  • Axios

  • 源码解读
  • vuex
深海鱼
2024-07-01
目录

总结与常见问题

到此我们已经将Vuex 3.0.1的源码已经全部解读完毕了。本文对整个源码进行总结,并列举一些常见问题。

# 一、总结

# 1. Vuex是一个Vue插件

Vuex 是一个状态管理库,也是一个Vue插件,它将Vue应用中的共享状态抽取出来,以集中式的方式管理。所有的Vue插件都应该是一个函数或者是一个具有install方法的对象。Vuex就是一个具有install方法的对象,当我们执行Vue.use(Vuex)时就会调用Vuex.install方法,将Vue作为参数传入。执行后经过如下处理过程:

  • 判断是否已经安装过,如果已经安装过,则不重复安装
  • 将传入的Vue构造函数赋值给全局的Vue变量,从而令Vue构造函数和Vuex关联,后续创建Store时创建Vue实例使用该构造函数
  • 在Vue2.0以上的版本中,混入beforeCreate钩子函数,在Vue2.0以下的版本使用重写Vue.prototype._init方法的方式,在初始化Vue实例时将Vuex的Store实例注入到所有的实例中。从而实现根应用下所有的子组件都可以访问到Store实例。

# 2. Store实例

Store类是Vuex的核心,Vuex所有的状态管理都是基于Store实例。Store实例中包含了state、getters、mutations、actions、modules等属性和方法。在初始化一个Store实例时,会执行Store类的构造函数new Store(options)。

options属性如下:

  • state:状态对象,默认为空对象
  • actions:action对象,默认为空对象
  • mutations:mutations对象,默认为空对象
  • getters:getters对象,默认为空对象
  • modules:模块对象,默认为空对象
  • plugins:插件列表,默认为空数组
  • strict:是否为严格模式,默认为false

执行过程如下:

  • 使用script引入时会自动安装Vuex
  • 通过options.state,获取state的值,options.state可以是函数,函数返回值作为state的值;state的默认值是空对象
  • 初始化各种属性:
    • _committing:一个布尔值,用于判断当前是否处于mutation中,默认为false
    • _committing:是否正在提交,默认值为false,当该值被标记为true时,则state允许被修改。
    • _actions:存放所有action的对象,默认值为空对象。
    • _actionSubscribers:存放action订阅者,默认值为空数组,在使用dispatch派发action时,会遍历并触发订阅者
    • _mutations:存放所有mutation的对象,默认值为空对象。
    • _wrappedGetters:存放所有getters的包装函数的对象,默认值为空对象。
    • _modules:根模块树,是Vuex模块化支持的基础,使用ModuleCollection类实例化,是具有一个root属性的模块树
    • _modulesNamespaceMap:模块命名空间映射,定义的Vuex模块都会被映射到该对象的属性中,辅助函数的模块会从该对象获取。
    • _subscribers:mutation订阅列表,默认值为空数组,在使用commit提交mutation时,会遍历该数组并执行订阅者
    • _watcherVM:一个Vue实例,用于触发watcher,是store.watchAPI实现的基础
    • strict:是否开启严格模式,从options中获取,默认值为false。在严格模式下,state只能通过mutation修改
  • 执行installModule(this, state, [], this._modules.root)安装根模块:
    • 带命名空间的模块存入_modulesNamespaceMap对象中
    • 将state转为嵌套的对象
    • 创建局部上下文,返回一个包含dispatch,commit,getters,state的对象
    • 注册mutations到_mutations,有命名空间的键名会带上命名空间,同名的mutation其处理函数存放在同一个数组里,处理函数只接收局部上文的state
    • 注册actions到_actions,有命名空间的键名会带上命名空间,同名的action其处理函数存放在同一个数组里,处理函数接收局部上下文和根上下文的state和getters作为参数
    • 注册getters,将getters包装后存到_wrappedGetters对象中,依次接收局部上下文的state、getters和根局部上下文的state、getters
    • 遍历子模块,递归安装子模块
  • 定义响应式数据
    • 创建_vm属性,其值为Vue实例,以state作为data.$$state选项传入,包装后的getters作为computed选项
    • 将store.getters代理至_vm实例的同名属性(计算属性)
    • 严格模式设置
    • 销毁旧的实例
  • 安装插件

实例化后的store还具有一套API供外部调用,这些API如下:

  • dispatch(type, payload):派发action,返回一个Promise对象
  • commit(type, payload, options):提交mutation,返回一个Promise对象
  • replaceState(state):替换根state
  • registerModule(path, module, options):注册动态模块
  • unregisterModule(path):注销动态模块
  • hasModule(path):判断是否已经注册同名的模块
  • watch(getter, cb, options):监听getter,返回一个watcher对象
  • subscribe(fn):订阅mutation,返回一个取消订阅的函数
  • subscribeAction(fn):订阅action,返回一个取消订阅的函数
  • hotUpdate(newOptions):热更新

# 3. 辅助方法

Vuex为我们提供了几个辅助函数,便于我们在项目中使用store实例的状态数据。函数列表如下:

  • mapState: 映射store的state属性到组件的computed属性中。
  • mapGetters:映射store的getters属性到组件的computed属性中。
  • mapActions:映射store的actions属性到组件的methods属性中。
  • mapMutations:映射store的mutations属性到组件的methods属性中。
  • createNamespacedHelpers:创建一个带命名空间的辅助函数,它们在使用前都已经绑定在了给定的命名空间。

# 4. 插件系统

Vuex提供插件机制来扩展其功功能,插件是一个函数,接收一个store实例作为参数。并且内置了devtoolPlugin插件和Logger插件。

Vuex完整的架构图如下:

Vuex

# 二、常见问题

# 1. 如果在mutation中执行异步操作会怎么样?

在严格模式下会提示不在mutation外部修改state。这是因为,执行mutation时会临时将_committing设置为true,执行完成后会同步将_committing恢复为原来的值。如果是个异步操作,此时_committing的值为false,所以会提示。虽然给出了提示,但是state的状态其实已经变化了,所以仍然会触发watcher,页面使用到了state依然会更新。

# 2. 如果不使用mutation直接修改state会怎样?

在严格模式下会提示不在mutation外部修改state,同理state的状态其实已经变化了,所以仍然会触发watcher,页面使用到了state依然会更新。

# 3. 辅助函数是如何通过命名空间查找到对应模块的state、getters、mutation和action的?

辅助函数会根据传入的命名空间,从store._modulesNamespaceMap找到对应的模块,每一个模块都有一个context属性,该属性是一个包含state、getters、commit、dispatch的局部上下文对象,从中可以获取以上的属性。而getters是还可以通过命名空间直接从store.getters获取,Vuex内部采用的第二种方式。

最近更新: 2024/07/01, 18:59
内置插件
Vue-Router源码解读

← 内置插件 Vue-Router源码解读→

最近更新
01
Axios源码解读
07-29
02
基于React16的Webpack升级与构建速度优化
07-09
03
Vue-Router源码解读
07-09
更多文章>
Theme by Vdoing | Copyright © 2024-2024 深海鱼 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式