关于vuex:手写vuex原理解析

应用vue过程中难免会用到vuex,然而很多时候咱们只晓得如何应用它但却不明确外部运行机制,上面咱们来简略手写一下vuex的实现过程。

简介

Vuex 是一个专为 Vue.js 利用程序开发的状态管理模式。其集中式的存储了利用所有组件的状态,并且制订了绝对应的规定以便保障组件状态能够朝着可预测的方向发生变化。

首先须要理解vuex的几个外围概念:

  • State 繁多状态树,惟一数据源
  • Mutation 状态更改函数
  • Action 蕴含任意异步操作
  • Getter state中派生出一些状态,相似计算属性
  • Module store模块宰割机制,
  • store 蕴含以上概念的容器

对这些概念不分明的能够观看vuex官网进行进一步理解:https://vuex.vuejs.org/zh/

vuex原理解析

首先vuex是一个插件,咱们须要去申明一个store类,还要有个install办法去挂载$store。
store的具体实现过程:

1、创立响应式的state,保留mutations,actions与getters。
2、实现commit依据用户传入type执行对应mutation。
3、实现dispatch依据传入的type生成对应的action,同时传递数据。
4、实现getters,依照getters定义对state派生数据。

首先设计vuex根本数据:

import Vue from 'vue'
import Vuex from './vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    counter: 0,
  },
  mutations: {
    add(state) {
      state.counter++
    }
  },
  actions: {
    // 参数怎么来的?
    add({ commit }) {
      // 业务逻辑组合或者异步
      setTimeout(() => {
        commit('add')
      }, 1000);
    }
  },
  getters: {
    doubleCounter: state => {
      return state.couter*2;
    },
  },
  modules: {
  }
})

1.对store类的申明,install办法实现。

let Vue;
// 申明Store类
class Store {
 constructor(options = {}) {

 this._vm = new Vue({
 // data中的值都会做响应化解决
     data: { 
        // 相当于总线
        $$state:options.state
     }
  });
 }

 get state() {
    // 存取器使之成为只读
    return this._vm._data.$$state 
 }

 set state(v) {
     console.error('please use replaceState to reset state'); 
 } }

function install(_Vue) {
 Vue = _Vue; 

 Vue.mixin({
     beforeCreate() { 
         if (this.$options.store) {
         // this.$options为Vue 实例的初始化选项
            Vue.prototype.$store = this.$options.store; 
         } 
     }
  });
}

export default { Store, install };

这里有两点值得注意,源码中state利用vue的data的响应式。利用存取器,把state设置成只读属性。
这里双$定义state第一次看上去必定有点不解,这里是为了Vue不做代理。

2.实现commit:依据用户传入type获取并执行对应mutation

class Store {
    constructor(options = {}) { 
        // 保留用户配置的mutations选项
        this._mutations = options.mutations || {}
    } 

    commit(type, payload) {  
        // 获取type对应的mutation  
        const entry = this._mutations[type]

        if (!entry) {
            console.error(`unknown mutation type: ${type}`);
            return 
        }
        // 指定上下文为Store实例  
        // 传递state给mutation entry(this.state, payload);
        entry(this.state, payload)
    }
}

这里的entry是mutations外面定义的add办法,payload是传入的参数。

3.实现actions:依据用户传入type获取并执行对应action

class Store {
  constructor(options) {
    this._actions = options.actions

    // 锁死commit,dispatch函数this指向
    const store = this
    const {commit, dispatch} = store
    this.commit = function boundCommit(type, payload) {
      commit.call(store, type, payload)
    }
    this.dispatch = function boundDispatch(type, payload) {
      dispatch.call(store, type, payload)
    }
  }

  // dispatch,执行异步工作或简单逻辑
  dispatch(type, payload) {
    // 1.获取action
    const entry = this._actions[type]

    if (!entry) {
      console.error('哎呦,没有这个action');
      return;
    }

    // 异步后果解决经常须要返回Promise
    return entry(this, payload)

  }
}

这里对dispatch和commit做了this的绑定,必须绑定commit上下文否则action中调用commit时可能出问题
3.实现getters:state的动静计算属性

class Store {
  constructor(options) {
    const store = this

    this._wrappedGetters = options.getters

    // 定义computed 选项
    const computed = {}
    this.getters = {}
    Object.keys(this._wrappedGetters).forEach(key => {
      // 获取用户定义的getter
      const fn = store._wrappedGetters[key]
      // 转换为computed能够应用无参数模式
      computed[key] = function() {
        return fn(store.state)
      }
      // 为getters定义只读属性
      Object.defineProperty(store.getters, key, {
        get: () => store._vm[key]
      })
    })

    this._vm = new Vue({
      // data中的值都会做响应化解决
      data: {
        $$state: options.state
      },
      // 利用vue的computed计算属性
      computed
    })
}

这里看起来简单认真拆分每一个看,其实很简略。

最终实现成果

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理