Vuex源码分析(二)-- state

Vuex源码分析(二)-- state

首先总结

  • stateStore实例的一个属性
  • 通过创建Store实例生成的state,根节点上的state始终包含全局state以及相应的模块名,不管子模块的namespaced是否为true
  • namespaced字段只影响[getters, mutations, actions] 的命名前缀
const store = new Vuex.Store({
	state: {a : 1}, // 这个state可以是一个对象,也可以是一个方法
	modules: { // 存放子模块的地方,module2为子模块的命名空间
		module2: {
			state: {b : 2}
		}
	}
})

vm.$store.state = { a : 1, module2 : { b : 2 } }

这里的state已经不像原始options那样很多层级了,那么Store的内部结构如何?又是如何简化 state 结构的呢?由于源码中存在很多非state相关处理,于是做了相应的简化处理

首先是构造器

export class Store {
  constructor (options = {}) {
    // new Store()时,如果Vue未注册Vuex,则直接注册
    if (!Vue && typeof window !== 'undefined' && window.Vue) {
      install(window.Vue)
    }
	...
	// 把state赋值给了 vm.data.$$state,getters赋值给了vm.computed
	// 然后使用vue的 $watch 方法,进行监控
	this._watcherVM = new Vue()
	// 这里直接处理options中的属性,将其生成一个Module树
	// 每个 Module 对象都包含[state, getters, mutations, actions, modules]属性
	// modules 是子模块,也是 Module 对象
    this._modules = new ModuleCollection(options)
	...
	// 处理完后 state = { a : 1 },此时还没有子模块的state
    const state = this._modules.root.state
	...
	// 汇总处理各模块对象上的[state, getters, mutations, actions]
	// 于是根节点上的state就包含了所有state
    installModule(this, state, [], this._modules.root)
	// destroy原来的this._watcherVM对象,然后新建一个new Vue() 对属性重新监控
    resetStoreVM(this, state)
  }

  get state () {
    return this._vm._data.$$state
  }
  // 提示不允许直接设置 state
  set state (v) {
    if (__DEV__) {
      assert(false, `use store.replaceState() to explicit replace store state.`)
    }
  }
}

然后是模块收集器ModuleCollection

根据从Store对象传来的options属性,生成一系列Module

export default class ModuleCollection {
  // rawRootModule ⇒ 原始options
  constructor (rawRootModule) {
    this.register([], rawRootModule, false)
  }
  /**
   * 根据 options 对象,生成模块
   * 
   * @path: 前置路径,是一个数组,目的是处理多 modules 的命名空间
   * @rawModule: 当前module的原始options对象
   */
  register (path, rawModule, runtime = true) {
    const newModule = new Module(rawModule, runtime)
    // 没有前置路径,表示根模块
    if (path.length === 0) {
      this.root = newModule
    } else {
      // 例:path = ['module1', 'module2', 'module3']
      // parent = this.root._children['module1']._children['module2']
      const parent = this.get(path.slice(0, -1))
      // parent.addChild('module3', newModule) ⇒ parent._children['module3'] = newModule
      parent.addChild(path[path.length - 1], newModule)
    }
    // 如果当前options.modules存在,依次建立子模块
    if (rawModule.modules) {
      forEachValue(rawModule.modules, (rawChildModule, key) => {
        this.register(path.concat(key), rawChildModule, runtime)
      })
    }
  }
}

每一个optons对象,都会生成一个Module对象,这个对象的_children对象会储存modules上的子模块,这个子模块也是一个Module对象

export default class Module {
  constructor (rawModule, runtime) {
    // _children 存放的也是Module对象
    this._children = Object.create(null)
    // 保存原始options对象
    this._rawModule = rawModule
    
    // this.state = options.state
    const rawState = rawModule.state
    // 这里表明 state 既可以传一个对象,也可以传一个方法
    this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}
  }
}

这个方法是简化state对象的核心方法

function installModule (store, rootState, path, module, hot) {
  const isRoot = !path.length

  // 如果不是根节点,或者不是热部署,将当前节点的state赋值给父节点的state上
  if (!isRoot && !hot) {
  	// getNestedState 表示获取根节点上指定路径上的state
  	
  	// 例: path = ['module1', 'module2']
  	// getNestedState(rootState, path.slice(0, -1)) ⇒ rootState['module1']
  	// Vue.set(rootState['module1'], path[last], module.state)
  	// 这样根节点上的state就赋值上了 module2 的state, 即 rootState['module1']['module2'] = module.state
    const parentState = getNestedState(rootState, path.slice(0, -1))
    const moduleName = path[path.length - 1]
    store._withCommit(() => {
      Vue.set(parentState, moduleName, module.state)
    })
  }
  // 遍历子模块,依次注册
  module.forEachChild((child, key) => {
    installModule(store, rootState, path.concat(key), child, hot)
  })
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值