VueX源码分析(5)

最终也是最重要的store.js,该文件主要涉及的内容如下:

  • Store类
  • genericSubscribe函数
  • resetStore函数
  • resetStoreVM函数
  • installModule函数
  • makeLocalContext函数
  • makeLocalGetters函数
  • registerMutation函数
  • registerAction函数
  • registerGetter函数
  • enableStrictMode函数
  • getNestedState函数
  • unifyObjectStyle函数
  • install函数
  • let Vue上面这些和这个Vue都在同一个作用域

install

  1. export function install (_Vue) {
  2. if (Vue && _Vue === Vue) {
  3. if (process.env.NODE_ENV !== 'production') {
  4. console.error(
  5. '[vuex] already installed. Vue.use(Vuex) should be called only once.'
  6. )
  7. }
  8. return
  9. }
  10. Vue = _Vue
  11. applyMixin(Vue)
  12. }

解析:

  • 主要是让所有组件都能拿到store,在组件生命周期beforeCreate期间给所有组件创建$store
  • 如果是开发环境还会判断是否使用Vue.use(Vuex)

unifyObjectStyle

  1. function unifyObjectStyle (type, payload, options) {
  2. if (isObject(type) && type.type) {
  3. options = payload
  4. payload = type
  5. type = type.type
  6. }
  7. if (process.env.NODE_ENV !== 'production') {
  8. assert(typeof type === 'string', `expects string as the type, but found ${typeof type}.`)
  9. }
  10. return { type, payload, options }
  11. }

解析:

  • 主要处理dispatch('pushTab', payload, options)dispatch({ type: 'pushTab', payload }, options)这种情况
  • 也即第一个参数可以是字符串,也可以是对象,就是由第一个参数决定采用什么样的方式传参。这个函数的目的就是支持不同风格的传参
  • 传参风格(方式),由传入的第一个参数类型决定

getNestedState

  1. function getNestedState (state, path) {
  2. return path.length
  3. ? path.reduce((state, key) => state[key], state)
  4. : state
  5. }

解析:

  • 和之前模块module中的path一样,path为空数组[]为非嵌套或根模块,{ shop: { card: { item: 1 } } }的path为['shop', 'card', 'item']
  • 就是通过迭代的方式获取状态item
  • 这样做的好处是:对象和数组都支持,如果是数组[{ name: 'getMe' }, { name: 'notMe' }],要获取'getMe'那么const path = [0, 'name']

enableStrictMode

  1. function enableStrictMode (store) {
  2. store._vm.$watch(function () { return this._data.$$state }, () => {
  3. if (process.env.NODE_ENV !== 'production') {
  4. assert(store._committing, `do not mutate vuex store state outside mutation handlers.`)
  5. }
  6. }, { deep: true, sync: true })
  7. }

解析:

  • $watch就是Vue.$watch,主要功能是:如果启动了严格模式,监控数据状态的改变是不是通过commit改变的。
  • 如果不是通过commit改变状态的,在开发模式下会提示。
  • VueX的状态是存在于一个Vue实例中的_data.$$stateStore._vm可以解释VueX为什么叫VueX
  • 可以说VueXVue的一个实例

genericSubscribe

  1. function genericSubscribe (fn, subs) {
  2. if (subs.indexOf(fn) < 0) {
  3. subs.push(fn)
  4. }
  5. return () => {
  6. const i = subs.indexOf(fn)
  7. if (i > -1) {
  8. subs.splice(i, 1)
  9. }
  10. }
  11. }

解析:

  • 订阅某个观察者,这里面subs是观察者,subs关联到某个状态,那个状态改变,会遍历subs调用里面的函数。
  • 返回的函数时可以取消订阅的,也即const unsubscribe = genericSubscribe(fn, subs),调用unsubscribe()就可以取消订阅

class Store

几个辅助函数和状态相关

  • resetStore:重置状态,类似重新开始游戏,会重新创建Store
  • resetStoreVM:Vuex的状态是存放在这个Vue实例的_data中
  • installModule:安装模块,注册模块
  • makeLocalContext:作用域模块中定义的getters,actions等的函数都会传入一个context
  • makeLocalGetters:作用域模块中定义getters细节
  • registerMutation:模块中的Mutation注册
  • registerAction:模块中的Action注册
  • registerGetter:模块中的Getter注册
  1. let Vue // bind on install
  2. export class Store {
  3. constructor (options = {}) {
  4. // Auto install if it is not done yet and `window` has `Vue`.
  5. // To allow users to avoid auto-installation in some cases,
  6. // this code should be placed here. See #731
  7. if (!Vue && typeof window !== 'undefined' && window.Vue) {
  8. install(window.Vue)
  9. }
  10. if (process.env.NODE_ENV !== 'production') {
  11. assert(Vue, `must call Vue.use(Vuex) before creating a store instance.`)
  12. assert(typeof Promise !== 'undefined', `vuex requires a Promise polyfill in this browser.`)
  13. assert(this instanceof Store, `store must be called with the new operator.`)
  14. }
  15. const {
  16. plugins = [],
  17. strict = false
  18. } = options
  19. // store internal state
  20. this._committing = false
  21. this._actions = Object.create(null)
  22. this._actionSubscribers = []
  23. this._mutations = Object.create(null)
  24. this._wrappedGetters = Object.create(null)
  25. this._modules = new ModuleCollection(options)
  26. this._modulesNamespaceMap = Object.create(null)
  27. this._subscribers = []
  28. this._watcherVM = new Vue()
  29. // bind commit and dispatch to self
  30. const store = this
  31. const { dispatch, commit } = this
  32. this.dispatch = function boundDispatch (type, payload) {
  33. return dispatch.call(store, type, payload)
  34. }
  35. this.commit = function boundCommit (type, payload, options) {
  36. return commit.call(store, type, payload, options)
  37. }
  38. // strict mode
  39. this.strict = strict
  40. const state = this._modules.root.state
  41. // init root module.
  42. // this also recursively registers all sub-modules
  43. // and collects all module getters inside this._wrappedGetters
  44. installModule(this, state, [], this._modules.root)
  45. // initialize the store vm, which is responsible for the reactivity
  46. // (also registers _wrappedGetters as computed properties)
  47. resetStoreVM(this, state)
  48. // apply plugins
  49. plugins.forEach(plugin => plugin(this))
  50. if (Vue.config.devtools) {
  51. devtoolPlugin(this)
  52. }
  53. }
  54. get state () {
  55. return this._vm._data.$$state
  56. }
  57. set state (v) {
  58. if (process.env.NODE_ENV !== 'production') {
  59. assert(false, `use store.replaceState() to explicit replace store state.`)
  60. }
  61. }
  62. commit (_type, _payload, _options) {
  63. // check object-style commit
  64. const {
  65. type,
  66. payload,
  67. options
  68. } = unifyObjectStyle(_type, _payload, _options)
  69. const mutation = { type, payload }
  70. const entry = this._mutations[type]
  71. if (!entry) {
  72. if (process.env.NODE_ENV !== 'production') {
  73. console.error(`[vuex] unknown mutation type: ${type}`)
  74. }
  75. return
  76. }
  77. this._withCommit(() => {
  78. entry.forEach(function commitIterator (handler) {
  79. handler(payload)
  80. })
  81. })
  82. this._subscribers.forEach(sub => sub(mutation, this.state))
  83. if (
  84. process.env.NODE_ENV !== 'production' &&
  85. options && options.silent
  86. ) {
  87. console.warn(
  88. `[vuex] mutation type: ${type}. Silent option has been removed. ` +
  89. 'Use the filter functionality in the vue-devtools'
  90. )
  91. }
  92. }
  93. dispatch (_type, _payload) {
  94. // check object-style dispatch
  95. const {
  96. type,
  97. payload
  98. } = unifyObjectStyle(_type, _payload)
  99. const action = { type, payload }
  100. const entry = this._actions[type]
  101. if (!entry) {
  102. if (process.env.NODE_ENV !== 'production') {
  103. console.error(`[vuex] unknown action type: ${type}`)
  104. }
  105. return
  106. }
  107. this._actionSubscribers.forEach(sub => sub(action, this.state))
  108. return entry.length > 1
  109. ? Promise.all(entry.map(handler => handler(payload)))
  110. : entry[0](payload)
  111. }
  112. subscribe (fn) {
  113. return genericSubscribe(fn, this._subscribers)
  114. }
  115. subscribeAction (fn) {
  116. return genericSubscribe(fn, this._actionSubscribers)
  117. }
  118. watch (getter, cb, options) {
  119. if (process.env.NODE_ENV !== 'production') {
  120. assert(typeof getter === 'function', `store.watch only accepts a function.`)
  121. }
  122. return this._watcherVM.$watch(() => getter(this.state, this.getters), cb, options)
  123. }
  124. replaceState (state) {
  125. this._withCommit(() => {
  126. this._vm._data.$$state = state
  127. })
  128. }
  129. registerModule (path, rawModule, options = {}) {
  130. if (typeof path === 'string') path = [path]
  131. if (process.env.NODE_ENV !== 'production') {
  132. assert(Array.isArray(path), `module path must be a string or an Array.`)
  133. assert(path.length > 0, 'cannot register the root module by using registerModule.')
  134. }
  135. this._modules.register(path, rawModule)
  136. installModule(this, this.state, path, this._modules.get(path), options.preserveState)
  137. // reset store to update getters...
  138. resetStoreVM(this, this.state)
  139. }
  140. unregisterModule (path) {
  141. if (typeof path === 'string') path = [path]
  142. if (process.env.NODE_ENV !== 'production') {
  143. assert(Array.isArray(path), `module path must be a string or an Array.`)
  144. }
  145. this._modules.unregister(path)
  146. this._withCommit(() => {
  147. const parentState = getNestedState(this.state, path.slice(0, -1))
  148. Vue.delete(parentState, path[path.length - 1])
  149. })
  150. resetStore(this)
  151. }
  152. hotUpdate (newOptions) {
  153. this._modules.update(newOptions)
  154. resetStore(this, true)
  155. }
  156. _withCommit (fn) {
  157. const committing = this._committing
  158. this._committing = true
  159. fn()
  160. this._committing = committing
  161. }
  162. }

解析:

  • install(window.Vue)如果是Vue2,通过mixins的方式添加beforeCreate钩子函数,把store传给任何继承这个Vue的实例(组件),所以所有组件都拥有一个$store的属性。也即每个组件都能拿到store。

  • 第二个断言判断是确保Vue在当前环境中,且需要Promise,强制Store作为构造函数。

  • 可配置项有两个值plugins和是否使用strict严格模式(只能通过commit改变状态),plugins一般用于开发调试

  • 将全局(非模块内)的dispatch和committhis绑定到store

Store类的静态属性

  • _committing:记录当前是否commit中
  • _actions:记录所有action的字段,有模块作用域的用'/'分隔
  • _actionSubscribers:全局的dispatch后遍历调用数组中的函数
  • _mutations:和actions一样
  • _wrappedGetters:不管是使用了模块还是全局的getter都存在于此
  • _modules:全局模块
  • _modulesNamespaceMap:所有模块全存于此,可通过namespace取出想要的模块
  • _subscribers:全局的commit调用之后,遍历调用数组中的函数
  • _watcherVM:Vue实例用于watch()函数
  • strict:是否使用严格模式,使用那么改变状态只能通过commit来改变状态
  • state:Store的所有state包含模块的
  • _vm:Vue的实例,VueX真正状态是存于这里Store._vm._data.$$state

installModule

  1. function installModule (store, rootState, path, module, hot) {
  2. const isRoot = !path.length
  3. const namespace = store._modules.getNamespace(path)
  4. // register in namespace map
  5. if (module.namespaced) {
  6. store._modulesNamespaceMap[namespace] = module
  7. }
  8. // set state
  9. if (!isRoot && !hot) {
  10. const parentState = getNestedState(rootState, path.slice(0, -1))
  11. const moduleName = path[path.length - 1]
  12. store._withCommit(() => {
  13. Vue.set(parentState, moduleName, module.state)
  14. })
  15. }
  16. const local = module.context = makeLocalContext(store, namespace, path)
  17. module.forEachMutation((mutation, key) => {
  18. const namespacedType = namespace + key
  19. registerMutation(store, namespacedType, mutation, local)
  20. })
  21. module.forEachAction((action, key) => {
  22. const type = action.root ? key : namespace + key
  23. const handler = action.handler || action
  24. registerAction(store, type, handler, local)
  25. })
  26. module.forEachGetter((getter, key) => {
  27. const namespacedType = namespace + key
  28. registerGetter(store, namespacedType, getter, local)
  29. })
  30. module.forEachChild((child, key) => {
  31. installModule(store, rootState, path.concat(key), child, hot)
  32. })
  33. }
  • 这个函数主要作用是安装模块,在初始化根模块的同时注册所有子模块,以及将所有getter(包括模块中的)收集到this._wrappedGetters中。
  • _modulesNamespaceMap存放所有模块,可以通过namespaced来获取模块(数据结构:哈希表)
  • Vue.set(parentState, moduleName, module.state)由于VueX是Vue的实例,Vue设置的状态,它的实例(VueX)可以继承
  • 创建每个模块的context

makeLocalContext

  1. /**
  2. * make localized dispatch, commit, getters and state
  3. * if there is no namespace, just use root ones
  4. */
  5. function makeLocalContext (store, namespace, path) {
  6. const noNamespace = namespace === ''
  7. const local = {
  8. dispatch: noNamespace ? store.dispatch : (_type, _payload, _options) => {
  9. const args = unifyObjectStyle(_type, _payload, _options)
  10. const { payload, options } = args
  11. let { type } = args
  12. if (!options || !options.root) {
  13. type = namespace + type
  14. if (process.env.NODE_ENV !== 'production' && !store._actions[type]) {
  15. console.error(`[vuex] unknown local action type: ${args.type}, global type: ${type}`)
  16. return
  17. }
  18. }
  19. return store.dispatch(type, payload)
  20. },
  21. commit: noNamespace ? store.commit : (_type, _payload, _options) => {
  22. const args = unifyObjectStyle(_type, _payload, _options)
  23. const { payload, options } = args
  24. let { type } = args
  25. if (!options || !options.root) {
  26. type = namespace + type
  27. if (process.env.NODE_ENV !== 'production' && !store._mutations[type]) {
  28. console.error(`[vuex] unknown local mutation type: ${args.type}, global type: ${type}`)
  29. return
  30. }
  31. }
  32. store.commit(type, payload, options)
  33. }
  34. }
  35. // getters and state object must be gotten lazily
  36. // because they will be changed by vm update
  37. Object.defineProperties(local, {
  38. getters: {
  39. get: noNamespace
  40. ? () => store.getters
  41. : () => makeLocalGetters(store, namespace)
  42. },
  43. state: {
  44. get: () => getNestedState(store.state, path)
  45. }
  46. })
  47. return local
  48. }
  • 这个函数主要创建局部的dispatch、commit、getters、state。存于context
  • 局部的意思是只取当前作用域模块的getters、state以及dispatch和commit,没有作用域就取全局的
  • get和state采用数据劫持和懒获取的方式
  • 懒:就是一个函数() => store.getters,只有调用这个函数才获取到所有getters,结合get就是只有引用这个属性才会获取所有getters
  • 懒获取就是把原本的操作封装成函数,在需要的时候调用该函数即可获得。实际上就是宏命令或者叫命令模式,用一个函数把一块要执行的命令封装起来。
  • () => fn()要留意的是:是fn()而不是fnfn()才是要执行的命令

makeLocalGetters

  1. function makeLocalGetters (store, namespace) {
  2. const gettersProxy = {}
  3. const splitPos = namespace.length
  4. Object.keys(store.getters).forEach(type => {
  5. // skip if the target getter is not match this namespace
  6. if (type.slice(0, splitPos) !== namespace) return
  7. // extract local getter type
  8. const localType = type.slice(splitPos)
  9. // Add a port to the getters proxy.
  10. // Define as getter property because
  11. // we do not want to evaluate the getters in this time.
  12. Object.defineProperty(gettersProxy, localType, {
  13. get: () => store.getters[type],
  14. enumerable: true
  15. })
  16. })
  17. return gettersProxy
  18. }
  • 先判断有没有匹配的作用域(getter = namespace + getterName),然后取出getter的名称
  • 通过代理的方式返回这个getter

resetStoreVM

  1. function resetStoreVM (store, state, hot) {
  2. const oldVm = store._vm
  3. // bind store public getters
  4. store.getters = {}
  5. const wrappedGetters = store._wrappedGetters
  6. const computed = {}
  7. forEachValue(wrappedGetters, (fn, key) => {
  8. // use computed to leverage its lazy-caching mechanism
  9. computed[key] = () => fn(store)
  10. Object.defineProperty(store.getters, key, {
  11. get: () => store._vm[key],
  12. enumerable: true // for local getters
  13. })
  14. })
  15. // use a Vue instance to store the state tree
  16. // suppress warnings just in case the user has added
  17. // some funky global mixins
  18. const silent = Vue.config.silent
  19. Vue.config.silent = true
  20. store._vm = new Vue({
  21. data: {
  22. $$state: state
  23. },
  24. computed
  25. })
  26. Vue.config.silent = silent
  27. // enable strict mode for new vm
  28. if (store.strict) {
  29. enableStrictMode(store)
  30. }
  31. if (oldVm) {
  32. if (hot) {
  33. // dispatch changes in all subscribed watchers
  34. // to force getter re-evaluation for hot reloading.
  35. store._withCommit(() => {
  36. oldVm._data.$$state = null
  37. })
  38. }
  39. Vue.nextTick(() => oldVm.$destroy())
  40. }
  41. }
  • 主要是重新设置store._vm的值
  • _vm的$$state保存的是store.state
  • _vmcomputedstore._wrappedGetters的值
  • 可以看出VueX的状态是存在于一个Vue实例的$data中的
  • (数据劫持+懒调用)和computed就是getter的实现原理,也是为什么getter有缓存的效果
  • 这个computed是VueX内部的_vm的,也可以认为就是getters

registerMutation

  1. function registerMutation (store, type, handler, local) {
  2. const entry = store._mutations[type] || (store._mutations[type] = [])
  3. entry.push(function wrappedMutationHandler (payload) {
  4. handler.call(store, local.state, payload)
  5. })
  6. }
  • 主要是按命名空间划分和收集不同命名空间的mutaion,以及把它们的this绑定为store
  • local.state如果有命名空间使用命名空间的,没有使用全局的
  • store._mutations[type],type就是命名空间,按命名空间来存放mutations

registerAction

  1. function registerAction (store, type, handler, local) {
  2. const entry = store._actions[type] || (store._actions[type] = [])
  3. entry.push(function wrappedActionHandler (payload, cb) {
  4. let res = handler.call(store, {
  5. dispatch: local.dispatch,
  6. commit: local.commit,
  7. getters: local.getters,
  8. state: local.state,
  9. rootGetters: store.getters,
  10. rootState: store.state
  11. }, payload, cb)
  12. if (!isPromise(res)) {
  13. res = Promise.resolve(res)
  14. }
  15. if (store._devtoolHook) {
  16. return res.catch(err => {
  17. store._devtoolHook.emit('vuex:error', err)
  18. throw err
  19. })
  20. } else {
  21. return res
  22. }
  23. })
  24. }
  • store._actions[type]存储结构和_mutations的一样,按命名空间来存储action
  • 同样绑定this为store,但是第一个参数传入了一个对象{ dispatch, commit, getters, state, rootGetters, rootState }
  • { dispatch, commit, getters, state }是局部local的
  • 运行后的结果是返回一个Promise

registerGetter

  1. function registerGetter (store, type, rawGetter, local) {
  2. if (store._wrappedGetters[type]) {
  3. if (process.env.NODE_ENV !== 'production') {
  4. console.error(`[vuex] duplicate getter key: ${type}`)
  5. }
  6. return
  7. }
  8. store._wrappedGetters[type] = function wrappedGetter (store) {
  9. return rawGetter(
  10. local.state, // local state
  11. local.getters, // local getters
  12. store.state, // root state
  13. store.getters // root getters
  14. )
  15. }
  16. }
  • store._wrappedGetters[type]由于所有getters放在一个对象,结构和actions、mutations的结构就不一样了,就是一个对象
  • 键值还是根据命名空间来生成
  • 传入四个参数(local.state, local.getters, store.state, store.getters);有命名空间,前面2个参数就是命名空间的,没有命名空间前面2个参数就是全局的

resetStore

  1. function resetStore (store, hot) {
  2. store._actions = Object.create(null)
  3. store._mutations = Object.create(null)
  4. store._wrappedGetters = Object.create(null)
  5. store._modulesNamespaceMap = Object.create(null)
  6. const state = store.state
  7. // init all modules
  8. installModule(store, state, [], store._modules.root, true)
  9. // reset vm
  10. resetStoreVM(store, state, hot)
  11. }
  • 这个会重新创建Store,整体的,整体替换旧的Store
  • 重新installModuleresetStoreVM

class Store 的方法

state()

  1. get state () {
  2. return this._vm._data.$$state
  3. }
  4. set state (v) {
  5. if (process.env.NODE_ENV !== 'production') {
  6. assert(false, `use store.replaceState() to explicit replace store state.`)
  7. }
  8. }
  • 获取的state是直接从store._vm._data.$$state中获取
  • 不可以直接设置state

replaceState

  1. replaceState (state) {
  2. this._withCommit(() => {
  3. this._vm._data.$$state = state
  4. })
  5. }
  • 替换状态是直接替换store._vm._data.$$state

commit

  1. commit (_type, _payload, _options) {
  2. // check object-style commit
  3. const {
  4. type,
  5. payload,
  6. options
  7. } = unifyObjectStyle(_type, _payload, _options)
  8. const mutation = { type, payload }
  9. const entry = this._mutations[type]
  10. if (!entry) {
  11. if (process.env.NODE_ENV !== 'production') {
  12. console.error(`[vuex] unknown mutation type: ${type}`)
  13. }
  14. return
  15. }
  16. this._withCommit(() => {
  17. entry.forEach(function commitIterator (handler) {
  18. handler(payload)
  19. })
  20. })
  21. this._subscribers.forEach(sub => sub(mutation, this.state))
  22. if (
  23. process.env.NODE_ENV !== 'production' &&
  24. options && options.silent
  25. ) {
  26. console.warn(
  27. `[vuex] mutation type: ${type}. Silent option has been removed. ` +
  28. 'Use the filter functionality in the vue-devtools'
  29. )
  30. }
  31. }
  • 全局的commit,由于_mutations存储的是所有的type(包括模块的),这个commit可以commit('shop/card')只要命名路径对
  • 调用完后,会发布_subscribers,遍历该数组调用回调

dispatch

  1. dispatch (_type, _payload) {
  2. // check object-style dispatch
  3. const {
  4. type,
  5. payload
  6. } = unifyObjectStyle(_type, _payload)
  7. const action = { type, payload }
  8. const entry = this._actions[type]
  9. if (!entry) {
  10. if (process.env.NODE_ENV !== 'production') {
  11. console.error(`[vuex] unknown action type: ${type}`)
  12. }
  13. return
  14. }
  15. this._actionSubscribers.forEach(sub => sub(action, this.state))
  16. return entry.length > 1
  17. ? Promise.all(entry.map(handler => handler(payload)))
  18. : entry[0](payload)
  19. }
  • 全局dispatch,和commit一样,_actions存放的是所有的action的type(包括模块的)
  • 调用完后会发布_actionSubscribers中订阅的回调函数
  • _actions[type]是一个数组,可以一个type不同处理,也即_actions[type] = [fn1, fn2, fn3, ...]
  • 如果出现一个type多个处理,就用Promise.all等到所有函数都调用完才统一处理(支持异步)

subscribe

  1. subscribe (fn) {
  2. return genericSubscribe(fn, this._subscribers)
  3. }
  • 订阅commit,只要调用全局的commit就调用,模块内的context.commit也是会调用全部的commit

subscribeAction

  1. subscribeAction (fn) {
  2. return genericSubscribe(fn, this._actionSubscribers)
  3. }
  • 订阅action,只要调用全局的action就调用,模块内的context.dispatch也是会调用全部的dispatch

watch

  1. watch (getter, cb, options) {
  2. if (process.env.NODE_ENV !== 'production') {
  3. assert(typeof getter === 'function', `store.watch only accepts a function.`)
  4. }
  5. return this._watcherVM.$watch(() => getter(this.state, this.getters), cb, options)
  6. }
  • 借用Vue$watch,观察想要监控的状态
  • 用这个函数就相当于创建一个getter,不同时可动态创建

动态模块

  • registerModule
  • unregisterModule
  • hotUpdate

registerModule

  1. registerModule (path, rawModule, options = {}) {
  2. if (typeof path === 'string') path = [path]
  3. if (process.env.NODE_ENV !== 'production') {
  4. assert(Array.isArray(path), `module path must be a string or an Array.`)
  5. assert(path.length > 0, 'cannot register the root module by using registerModule.')
  6. }
  7. this._modules.register(path, rawModule)
  8. installModule(this, this.state, path, this._modules.get(path), options.preserveState)
  9. // reset store to update getters...
  10. resetStoreVM(this, this.state)
  11. }
  • 动态注册模块
  • 注册一个模块会重新创建Storestore._vm
  • installModuleresetStoreVM这两个函数很总要,涉及到性能,重点、重点

unregisterModule

  1. unregisterModule (path) {
  2. if (typeof path === 'string') path = [path]
  3. if (process.env.NODE_ENV !== 'production') {
  4. assert(Array.isArray(path), `module path must be a string or an Array.`)
  5. }
  6. this._modules.unregister(path)
  7. this._withCommit(() => {
  8. const parentState = getNestedState(this.state, path.slice(0, -1))
  9. Vue.delete(parentState, path[path.length - 1])
  10. })
  11. resetStore(this)
  12. }
  • 注销模块
  • Vue.delete(parentState, path[path.length - 1])resetStore(this)
  • 还是会重新创建Store_vm

hotUpdate

  1. hotUpdate (newOptions) {
  2. this._modules.update(newOptions)
  3. resetStore(this, true)
  4. }
  • 更新模块
  • resetStore(this, true),还是会重新创建Store_vm

很重要的3个函数

  • resetStore:包含resetStoreVMinstallModule
  • resetStoreVM
  • installModule

VueX源码分析(5)的更多相关文章

  1. VueX源码分析(3)

    VueX源码分析(3) 还剩余 /module /plugins store.js /plugins/devtool.js const devtoolHook = typeof window !== ...

  2. VueX源码分析(4)

    VueX源码分析(4) /module store.js /module/module.js import { forEachValue } from '../util' // Base data s ...

  3. VueX源码分析(2)

    VueX源码分析(2) 剩余内容 /module /plugins helpers.js store.js helpers要从底部开始分析比较好.也即先从辅助函数开始再分析那4个map函数mapSta ...

  4. VueX源码分析(1)

    VueX源码分析(1) 文件架构如下 /module /plugins helpers.js index.esm.js index.js store.js util.js util.js 先从最简单的 ...

  5. 逐行粒度的vuex源码分析

    vuex源码分析 了解vuex 什么是vuex vuex是一个为vue进行统一状态管理的状态管理器,主要分为state, getters, mutations, actions几个部分,vue组件基于 ...

  6. vuex源码分析3.0.1(原创)

    前言 chapter1 store构造函数 1.constructor 2.get state和set state 3.commit 4.dispatch 5.subscribe和subscribeA ...

  7. vuex 源码分析(七) module和namespaced 详解

    当项目非常大时,如果所有的状态都集中放到一个对象中,store 对象就有可能变得相当臃肿. 为了解决这个问题,Vuex允许我们将 store 分割成模块(module).每个模块拥有自己的 state ...

  8. vuex 源码分析(六) 辅助函数 详解

    对于state.getter.mutation.action来说,如果每次使用的时候都用this.$store.state.this.$store.getter等引用,会比较麻烦,代码也重复和冗余,我 ...

  9. vuex 源码分析(五) action 详解

    action类似于mutation,不同的是Action提交的是mutation,而不是直接变更状态,而且action里可以包含任意异步操作,每个mutation的参数1是一个对象,可以包含如下六个属 ...

随机推荐

  1. js index of()用法

    含义: indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置.(工作中常用) 提示和注释: 注释:indexOf() 方法对大小写敏感! 注释:如果要检索的字符串值没有出现,则该方 ...

  2. 【分享】利用WMITool解决浏览器主页被hao123劫持问题

    我在别处发的帖子 http://www.52pojie.cn/thread-607115-1-1.html

  3. Luogu P2624 [HNOI2008]明明的烦恼 Prufer+组合+高精

    好的我把标准版过了... 设$ r_i$为$i$的度数 首先,我们设 $ sum = \Sigma r_i-1$,$ tot $ 为所有能够确定度数的点 所以我们有 $ C ^ {sum} _{n-2 ...

  4. 洛谷2747(不相交路线、dp)

    要点 反思:以前是在紫书上做过的-- \(dp[i][j]\)是从1引两条路到达i.j的最大值 为了不相交,则\(dp[i][i]\)都是非法的,不转移它,也不用它转移 #include <cs ...

  5. lifecycle-mapping-metadata.xml

    <?xml version="1.0" encoding="UTF-8"?> <lifecycleMappingMetadata> &l ...

  6. Java 中常用的数据源

    数据源:存储了所有建立数据库连接的信息.就象通过指定文件名你可以在文件系统中找到文件一样,通过提供正确的数据源名称,你可以找到相应的数据库连接. 1.JNDI方式创建DataSource 1.1 配置 ...

  7. Linux与DOS的常用命令比较

    命令类型 DOS Linux DOS示例 Linux示例 复制文件   copy cp copy c:\teacher1\file1 d:\tmp cp /home/teacher1/file1 /t ...

  8. Spark-2.4.0源码:sparkContext

    在看sparkContext之前,先回顾一下Scala的语法.Scala构造函数分主构造和辅构造函数,辅构造函数是关键字def+this定义的,而类中不在方法体也不在辅构造函数中的代码就是主构造函数, ...

  9. Python 为threading.Thread添加 terminate

    import threading import inspect import ctypes def _async_raise(tid, exc_type): """rai ...

  10. 使用AOP监控用户操作并插入数据库

    引入依赖 <!--spring切面aop依赖--> <dependency> <groupId>org.springframework.boot</group ...