vuex基本原理浅析

534 阅读2分钟

vuex基本使用

juejin.cn/post/690600…

juejin.cn/post/684490…

// store/index.js
import Vue from 'vue'
import Vuex from '../vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  plugins: [],
  state: {
    time: 1,
    userInfo: {
      avatar: '',
      account_name: '',
      name: ''
    },
  },
  getters: {
    getTime (state) {
      console.log('1212',state)
      return state.time
    }
  },
  mutations: {
    updateTime(state, payload){
      state.time = payload
    }
  },
  actions: {
    operateGrou({ commit }) {
      // commit('updateTime', 100)
      return Promise.resolve().then(()=>{
        return {
          rows: [1,2,3]
        }
      })
    }
  }})

// main.js
import Vue from "vue";
import App from "./App.vue";
import store from "./store";

new Vue({
  // 为了在 Vue 组件中访问 this.$store property,你需要为 Vue 实例提供创建好的 store。
  // Vuex 提供了一个从根组件向所有子组件,以 store 选项的方式“注入”该 store 的机制
  store,    
  render: h => h(App)
}).$mount("#app");

vuex实现原理

tech.meituan.com/2017/04/27/…

www.bilibili.com/video/BV186…


// vuex基本思想

let myVue
class Store{
    // 这里options获取到的是用户new Store实例时传入所有属性
    constructor(options){
        // 1. state实现
        // 核心点:这里将state借助vue设置成响应式。这也是vuex只能用于vue的一个原因
        this.vm = new myVue({
            data: {
                return {
                    state: options.state
                }
            }
        })
        // 将this.state的获取写成函数的类属性访问器形式,便于扩展
        // this.state = this.vm.state
        
        // 2. getters实现
        let getters = options.getters
        this.getters = {}
        // 因为getters传入的是个对象,对象中属性全部是函数,但是使用时确是当做属性使用,所以这里需要借助Object.defineProperty实现(就跟计算属性的实现方式一样)
        Object.keys(getters).forEach(getterName => {
            Object.defineProperty(this.getters, getterName, {
                get: () => {
                    // getters[getterName] 获取到函数
                    return getters[getterName](this.state)
                }
            })
        })
        
        // 3. mutations实现(结合commit方法)(发布订阅模式)
        let mutations = options.mutations
        this.mutations = {}
        Object.keys(mutations).forEach(mutationName => {
            this.mutations[mutationName] = (payLoad) => {
                mutations[mutationName](state, payLoad)
            }
        })
        
        // 4. actions实现(发布订阅模式)
        let actions = options.actions
        this.actions = {}
        Object.keys(actions).forEach(actionName => {
            this.actions[actionName] = (payLoad) => {
                actions[actionName](this, payLoad)
            }
        })
        
        
        
        
    }
    // 类属性访问器
    get state(){
        return this.vm.state
    }
    
    // 发布的时候回找对应mutationName的函数执行
    commit = (mutationName, payLoad) => {
        this.mutations[mutationName](payLoad)
    },
    
    // 发布的时候回找对应actionName的函数执行
    dispatch = (actionName, payLoad) => {
        this.actions[actionName](payLoad)
    }

}


// vuex的插件使用方式:Vue.use(Vuex)
const install  = (_Vue) => {
    // 这里插件默认传入Vue构造函数,使用临时变量myVue进行接收,这样就不需要vuex库中再导入Vue库了
    myVue = _Vue
    
    // 核心点:借助`mixin`
    // 将vue的store直接放在原型上,不对, 因为这样会导致所有的vue实例全部都有store属性; 
    // 这里只从当前根实例开始  所有根实例的子组件才有$store

    myVue.mixin({
        // 组件的创造过程先父后子
        beforeCreate(){
            // 把父组件的store属性,放到每个组件的实例上
            if(this.$options.store){ // 根实例
                this.$store = this.$options.store
            } else {
                this.$store = this.$parent && this.$parent.$store
            }
        }
    })
}

export {
    Store,
    install
}

actions异步操作实现

借助Promise.all依次处理完所有的异步函数,并将处理之后的结果一起返回

// dispatch实现的是actions的异步操作(核心思想发布订阅)
dispatch方法在 (_type, _payload) {
  // check object-style dispatch
  const {
      type,
      payload
  } = unifyObjectStyle(_type, _payload) // 配置参数处理

  // entry是当前type下所有action处理函数集合
  const entry = this._actions[type]
  if (!entry) {
    console.error(`[vuex] unknown action type: ${type}`)
    return
  }
  // 当entry的函数个数大于1时,采用Promise.all,依次处理完所有的函数回调,然后将结果返回
  return entry.length > 1
      ? Promise.all(entry.map(handler => handler(payload)))
      : entry[0](payload)
}
// commit主要实现的mutations的同步操作(核心思想发布订阅)
commit (_type, _payload, _options) {
  // check object-style commit
  const {
      type,
      payload,
      options
  } = unifyObjectStyle(_type, _payload, _options)

  const mutation = { type, payload }
  const entry = this._mutations[type]
  if (!entry) {
    console.error(`[vuex] unknown mutation type: ${type}`)
    return
  }
  // 专用修改state方法,其他修改state方法均是非法修改
  this._withCommit(() => {
    entry.forEach(function commitIterator (handler) {
      handler(payload)
    })
  })
  
  // 订阅者函数遍历执行,传入当前的mutation对象和当前的state
  this._subscribers.forEach(sub => sub(mutation, this.state))

  if (options && options.silent) {
    console.warn(
        `[vuex] mutation type: ${type}. Silent option has been removed. ` +
        'Use the filter functionality in the vue-devtools'
    )
  }
}