乐趣区

关于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
    })
}

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

最终实现成果

退出移动版