vue源码之vuex的基本实现

186 阅读1分钟

vuex

核⼼概念

  • state 状态、数据
  • mutations 更改状态的函数
  • actions 异步操作
  • store 包含以上概念的容器

测试用例

store/index.js

import Vue from 'vue'
import Vuex from './my-vuex.js'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        counter: 1
    },
    mutations: {
        add(state) {
            state.counter++
        }
    },
    actions: {
        add({ commit }) {
            setTimeout(() => {
                commit('add')
            }, 1000)
        }
    },
    getters: {
        doubleCounter(state) {
            return state.counter * 2
        }
    }
)}
<p @click="$store.commit('add')">counter: {{$store.state.counter}}</p> 
<p @click="$store.dispatch('add')">async counter: {{$store.state.counter}}</p>
<p>double:{{$store.getters.doubleCounter}}</p>

任务分析

  • 实现插件
  • 实现Store类
    • 维持⼀个响应式状态state
    • 实现commit()
    • 实现dispatch()
    • getters
  • 挂载$store

初始化:Store声明、install实现,my-vuex.js:

let Vue
class Store {
    constructor(options = {}) {
        this._vm = new Vue({
            data: {
                $$state: options.state
            }
        })
    }
    get state() {
        return this._vm._data.$$state
    }
    set state(v) {
        // console.error('please use replaceState to reset state')
        return
    }
}
function install(_Vue) {
    Vue = _Vue
    Vue.mixin({
        beforeCreate() {
            if (this.$options.store) {
                Vue.prototype.$store = this.$options.store
            }
        }
    })
}
export default {
    Store,
    install
}
export default { Vuex, install }

实现commit:根据⽤户传⼊type获取并执⾏对应mutation

class Store {
    constructor(options = {}) {
        this._mutation = options.mutations || {}
        this.commit = this.commit.bind(this)
    }
    coommit(type, payload) {
        const mutation = this._mutations[type]
        if (!mutation) {
            // console.error(`unknown mutation type: ${type}`)
            return
        }
        mutation(this.state, payload)
    }
}

实现actions:根据⽤户传⼊type获取并执⾏对应action

class Store {
    constructor(options = {}) {
        this._actions = options.actions || {}
        this.dispatch = this.dispatch.bind(this)
    }
    dispatch(type, payload) {
        const action = this._actions[type]
        if (!action) {
            // console.error(`unknown action type: ${type}`)
            return
        }
        action(this, payload)
    }
}
//
class Vuex {
    constructor(options = {}) {
        this._actions = options.actions || {}
        this.dispatch = this.dipatch.bind(this)
    }
    dispatch(type, payload) {
        const action = this._actions[type]
        if (!action) {
            console.error(`unknown action type: ${type}`)
            return
        }
        action(this, payload)
    }
}

实现getters

class Store {
    constructor(options = {}) {
        this._wrapperGetters = options.getters || {}
        this.getters = {}
        const computed = {}
        const store = this
        // computed 属性中函数不带参数,封装一层
        Object.keys(store._wrapperGetters).forEach(key => {
            const fn = store._wrapperGetters[key]
            computed[key] = function () {
                return fn(store.state)
            }
            Object.defineProperty(store.getters, key, {
                get: () => {
                    // computed中执行
                    return store._vm[key]
                }
            })
        })
        this._vm = new Vue({
            data: {
                $$state: options.state
            },
            computed
        })
    }
}

源码github地址