VueX源码分析(4)
VueX源码分析(4)
/module
store.js
/module/module.js
import { forEachValue } from '../util'
// Base data struct for store's module, package with some attribute and method
export default class Module {
constructor (rawModule, runtime) {
this.runtime = runtime
// Store some children item
this._children = Object.create(null)
// Store the origin module object which passed by programmer
this._rawModule = rawModule
const rawState = rawModule.state
// Store the origin module's state
this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}
}
get namespaced () {
return !!this._rawModule.namespaced
}
addChild (key, module) {
this._children[key] = module
}
removeChild (key) {
delete this._children[key]
}
getChild (key) {
return this._children[key]
}
update (rawModule) {
this._rawModule.namespaced = rawModule.namespaced
if (rawModule.actions) {
this._rawModule.actions = rawModule.actions
}
if (rawModule.mutations) {
this._rawModule.mutations = rawModule.mutations
}
if (rawModule.getters) {
this._rawModule.getters = rawModule.getters
}
}
forEachChild (fn) {
forEachValue(this._children, fn)
}
forEachGetter (fn) {
if (this._rawModule.getters) {
forEachValue(this._rawModule.getters, fn)
}
}
forEachAction (fn) {
if (this._rawModule.actions) {
forEachValue(this._rawModule.actions, fn)
}
}
forEachMutation (fn) {
if (this._rawModule.mutations) {
forEachValue(this._rawModule.mutations, fn)
}
}
}
解析:
Module
是store模块的类,基本模块的静态属性和一些方法rawModule
就是我们定义的模块对象{ namespaced, state, actions, mutations, getters }
this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}
定义状态可以用函数的方式定义的,这里要先判断状态是不是函数,是函数要执行函数后的值。_children
记录嵌套模块的模块{ state, modules: { modules: {} } }
namespaced
就是是否使用命名空间addChild、removeChild、getChild
是嵌套模块的一些操作方法- 还有一些遍历的方法但是只有
children、getters、actions、mutations
的遍历,没有this.state
,那个update
模块也是,不会更新state
- 更新只更新
namespaced、actions、mutations、getters
/module/module-collection.js
主要类ModuleCollection
,还有一些辅助函数,先分析辅助函数再分析主要类。
主要将所有模块合并的类。
断言函数(只在开发者环境起作用)
const functionAssert = {
assert: value => typeof value === 'function',
expected: 'function'
}
const objectAssert = {
assert: value => typeof value === 'function' ||
(typeof value === 'object' && typeof value.handler === 'function'),
expected: 'function or object with "handler" function'
}
const assertTypes = {
getters: functionAssert,
mutations: functionAssert,
actions: objectAssert
}
function assertRawModule (path, rawModule) {
Object.keys(assertTypes).forEach(key => {
if (!rawModule[key]) return
const assertOptions = assertTypes[key]
forEachValue(rawModule[key], (value, type) => {
assert(
assertOptions.assert(value),
makeAssertionMessage(path, key, type, value, assertOptions.expected)
)
})
})
}
function makeAssertionMessage (path, key, type, value, expected) {
let buf = `${key} should be ${expected} but "${key}.${type}"`
if (path.length > 0) {
buf += ` in module "${path.join('.')}"`
}
buf += ` is ${JSON.stringify(value)}.`
return buf
}
解析:
path
是嵌套模块的名称。如根模块为[]
,嵌套模块shop/card
为['shop', 'card']
。主要功能是模块的寻址路径,可以根据这个路径获取该模块。makeAssertionMessage(path, key, type, value, expected)
中的key
就是我们自定义模块的字段:如state、mutations
等,这个断言就是判断我们定义的字段命是否符合要求。
ModuleCollection
export default class ModuleCollection {
constructor (rawRootModule) {
// register root module (Vuex.Store options)
this.register([], rawRootModule, false)
}
get (path) {
return path.reduce((module, key) => {
return module.getChild(key)
}, this.root)
}
getNamespace (path) {
let module = this.root
return path.reduce((namespace, key) => {
module = module.getChild(key)
return namespace + (module.namespaced ? key + '/' : '')
}, '')
}
update (rawRootModule) {
update([], this.root, rawRootModule)
}
register (path, rawModule, runtime = true) {
if (process.env.NODE_ENV !== 'production') {
assertRawModule(path, rawModule)
}
const newModule = new Module(rawModule, runtime)
if (path.length === 0) {
this.root = newModule
} else {
const parent = this.get(path.slice(0, -1))
parent.addChild(path[path.length - 1], newModule)
}
// register nested modules
if (rawModule.modules) {
forEachValue(rawModule.modules, (rawChildModule, key) => {
this.register(path.concat(key), rawChildModule, runtime)
})
}
}
unregister (path) {
const parent = this.get(path.slice(0, -1))
const key = path[path.length - 1]
if (!parent.getChild(key).runtime) return
parent.removeChild(key)
}
}
function update (path, targetModule, newModule) {
if (process.env.NODE_ENV !== 'production') {
assertRawModule(path, newModule)
}
// update target module
targetModule.update(newModule)
// update nested modules
if (newModule.modules) {
for (const key in newModule.modules) {
if (!targetModule.getChild(key)) {
if (process.env.NODE_ENV !== 'production') {
console.warn(
`[vuex] trying to add a new module '${key}' on hot reloading, ` +
'manual reload is needed'
)
}
return
}
update(
path.concat(key),
targetModule.getChild(key),
newModule.modules[key]
)
}
}
}
解析:
- 主要功能是将所有模块合并起来,以及注册和注销所有模块。
register
就是将我们自己定义的对象模块new Module(自己定义的对象模块)
,这个注册可以递归地注册所有模块,包括嵌套的unregister
是module.js
文件中的delete this._children[key]
是直接调用delete删除this.root
就是最外层的modules
VueX源码分析(4)的更多相关文章
- VueX源码分析(5)
VueX源码分析(5) 最终也是最重要的store.js,该文件主要涉及的内容如下: Store类 genericSubscribe函数 resetStore函数 resetStoreVM函数 ins ...
- VueX源码分析(3)
VueX源码分析(3) 还剩余 /module /plugins store.js /plugins/devtool.js const devtoolHook = typeof window !== ...
- VueX源码分析(2)
VueX源码分析(2) 剩余内容 /module /plugins helpers.js store.js helpers要从底部开始分析比较好.也即先从辅助函数开始再分析那4个map函数mapSta ...
- VueX源码分析(1)
VueX源码分析(1) 文件架构如下 /module /plugins helpers.js index.esm.js index.js store.js util.js util.js 先从最简单的 ...
- 逐行粒度的vuex源码分析
vuex源码分析 了解vuex 什么是vuex vuex是一个为vue进行统一状态管理的状态管理器,主要分为state, getters, mutations, actions几个部分,vue组件基于 ...
- vuex源码分析3.0.1(原创)
前言 chapter1 store构造函数 1.constructor 2.get state和set state 3.commit 4.dispatch 5.subscribe和subscribeA ...
- vuex 源码分析(七) module和namespaced 详解
当项目非常大时,如果所有的状态都集中放到一个对象中,store 对象就有可能变得相当臃肿. 为了解决这个问题,Vuex允许我们将 store 分割成模块(module).每个模块拥有自己的 state ...
- vuex 源码分析(六) 辅助函数 详解
对于state.getter.mutation.action来说,如果每次使用的时候都用this.$store.state.this.$store.getter等引用,会比较麻烦,代码也重复和冗余,我 ...
- vuex 源码分析(五) action 详解
action类似于mutation,不同的是Action提交的是mutation,而不是直接变更状态,而且action里可以包含任意异步操作,每个mutation的参数1是一个对象,可以包含如下六个属 ...
随机推荐
- jquery 插件的实现和优化
1.menus 实现: $.fn.menu=function(options){ var $this=$(this); var cross='<div class="zhiniu_cr ...
- React中的代码分割
代码分割想要解决的问题是:经打包工具
- jsp内置对象作用域白话演示
内置对象就是JSP中不需要自己定义和声明的对象,可以在JSP中直接使用.JSP中有9大内置对象,它们有两个常用的方法:setAttribute("key","value& ...
- PAT甲级——1107 Social Clusters (并查集)
本文同步发布在CSDN:https://blog.csdn.net/weixin_44385565/article/details/90409731 1107 Social Clusters (30 ...
- Jmeter 跨线程组传递参数 之两种方法
终于搞定了Jmeter跨线程组之间传递参数,这样就不用每次发送请求B之前,都需要同时发送一下登录接口(因为同一个线程组下的请求是同时发送的),只需要发送一次登录请求,请求B直接用登录请求的参数即可,直 ...
- VS 小插件 之 编辑器背景图片
一.引言 不知道标题的名字我描述的是否正确哈,其实就是用VS写代码的时候,背景一般都是纯白 或者 纯黑(看主题而定),那么我前段时间发现 只需要一个VS插件,居然可以给VS设置背景图片,甚至还可以循环 ...
- 记录一个修改application.properties时遇到的坑
有一个需求是会频繁修改配置文件中的常量,为了方便就会用unzip解压war包,修改propertites中的值后重新打war 包,部署,但是发现修改的值没有起作用,,一直在纠结...后来发现其实在编译 ...
- HDU 1027 G - Can you answer these queries?
http://acm.hdu.edu.cn/showproblem.php?pid=4027 Can you answer these queries? Time Limit: 4000/2000 M ...
- JAVA分包下项目部分代码存储
一.注册时姓名去重和符合汉字格式: // 新用户申请加入 public void NewHuman() { System.out.println("========新会员申请加入页面==== ...
- leetcode84 Largest Rectangle in Histogram
思路: 使用单调栈计算每个位置左边第一个比它矮的位置和右边第一个比它矮的位置即可. 实现: #include <bits/stdc++.h> using namespace std; cl ...