vuex源码学习笔记

474 阅读1分钟

vuex 使用方法

import Vuex from 'vuex'
    import Vue from 'vue'
    Vue.use(Vuex)
    export default new Vuex.store({
        state = {},
        getters = {},
        mutations = {},
        actions = {}
    })

vue.use() 方法

vue.use()方法必须包含install方法,目的就是把插件挂载到vue上 vue-router, vuex都是同样的原理
install方法的实现

let Vue
    let install = (_Vue) => {
        Vue = _Vue
        // 给所有的组建均挂载
        Vue.mixin({
            beforeCreate () {
                if (this.$options && this.$options.store) {
                    this.$store = this.$options.store
                } else {
                    this.$store = this.$parent && this.$parent.$store
                }
            }
        })
    }

Store函数的实现

class Store {
        constructor(options) {
            const { state } = options
            this.getters = Object.create(null)
            this.actions = Object.create(null)
            this.mutations = Object.create(null)
            // module收集器
            this.modules = new ModuleCollection(options)
            this._vm = new Vue({
                data: {
                    state
                }
            })
            const { diapatch, commit } = this
            this.dispatch = (type) => {
                return dispatch.call(this, type)
            }
            this.commit = () => {
                return commit.call(this, type)
            }
            // 初始化module,同时递归注册所有module
            installModule(this, state, [], this.modules.root)
        }

        get state () {
            return this._vm.state
        }

        dispatch (type) {
            this.actions[type].forEach(fn => fn())
        }

        commit (type) {
            this.mutations[type].forEach(fn => fn())
        }
    }

收集所有module

ModuleCollection 主要将传入的 options 对象整个构造为一个 module 对象, 并循环调用 register 为其中的 modules 属性进行模块注册, 使其都成为 module 对象, 最后 options 对象被构造成一个完整的组件树.

 class ModuleCollection {
    constructor (options) {
        this.register([], options)
    }
    register (path, rawModule) {
        let newModule = {
            _raw: rawModule,
            _children: {},
            state: rawModule.state
        }
        if (path.length === 0 ) {
            this.root = newModule
        } else {
            let parent = path.slice(0, -1).reduce((root, current) => {
                return root._children[current]
            }, this.root)
            parent._children[path[path.length - 1]] = newModule
        }

        if (rawModule.modules) {
            forEach(rawModule.modules, (childName, module) => {
                this.register(path.concat[childName], module)
            })
        }
    }
}

初始化installModule函数的实现

注册mutation、action以及getter,同时递归安装所有子module。

function installModule (store, rootState, path, rootModule) {
    if (path.length > 0 ) {
       let parent =  path.slice(0, -1).reduce((root, current) => {
            return root._children[current]
        }, rootModule)
        Vue.set(parent, path[path.length - 1], rootModule.state)
    }
    if (rootModule._raw.getters) {
        forEach(rootModule._raw.getters, (getterName, getterFn) => {
            Object.defineProperty(store.getters, getterName, {
                get:  () => {
                    return getterFn(rootModule.store)
                }
            })
        })
    }

    if (rootModule._raw.actions) {
        forEach(rootModule._raw.actions, (actionName, actionFn) => {
            let entry = store.actions[actionName] || (store.actions[actionName] = [])
            entry.push(() => {
                actionFn.call(store, store)
            })
        })
    }

    if (rootModule._raw.mutations) {
        forEach(rootModule._raw.mutations, (mutationsName, mutationsFn) => {
            let entry = store.mutations[mutationsName] || (store.mutations[mutationsName] = [])
            entry.push(() => {
                mutationsFn.call(store, rootModule.store)
            })
        })
    }

    forEach(rootModule._children, (childName, module) => {
        installModule(store, rootState, path.concat(childName), module)
    })

}

参考资料:
Vuex源码阅读分析