Vuex简单实现

146 阅读1分钟

最近在看了vuex源码相关实现,这里只是简单实现一下state,getters,mutations,actions,不带module的,完整的实现可以在github查看github.com/Xaw-xu/vuex

入口文件 index.js

import {Store,install} from './store'

export {
    Store,install//install 为组件的安装方法,Vue.use()进行安装
}

export default {
    Store,install
}
// 以两种方式导出,可以以不同的方式引入

store.js

export let _Vue; // 这里用来存储Vue
export class Store {
}
// 我们在每个组件中都可以以this.$store拿到数据,核心就是用mixin在组件生命周期中进行混入,每一个组件都会挂载一个$store
export const install = (Vue) => {
  _Vue = Vue; // Vue.use()会执行插件的install方法,将Vue传入进来,这里存一下,在store类中会用到
  Vue.mixin({
    beforeCreate() {
        // 我们使用的时候会在根实例中传入一个store
        // new Vue({
        //   router,
        //   store,
        //   render: (h) => h(App),
        // }).$mount("#app");

      if (this.$options.store) {// 在根组件中可以用this.$options.store拿到store
        this.$store = this.$options.store;
      } else {
        // 对于子组件直接去取父级的store进行挂载,最后所有的组件中都可以访问到store
        if (this.$parent && this.$parent.$store) {
          this.$store = this.$parent.$store;
        }
      }
    },
  });
};

state 实现

export class Store {
  constructor(options) {
   //这里的options.state 即为用户new Vuex.Store({state:{}})时传入的state
   //Vuex数据修改后视图可以更新实际上内部就是new了一个vue实例
   //Vue中定义数据,属性名如果是$开头,数据是不会被代理到实例上的,也就是通过this._vm.$$state取值是取不到的
    this._vm = new _Vue({
      data() {
        return {
          $$state: options.state,//$标识表示内部的状态
        };
      },
    });
  }
  get state() {
    //可以通过_data访问到
    return this._vm._data.$$state;
  }
}

getters实现

工具函数
export const forEach = (obj = {}, fn) => {
  Object.keys(obj).forEach((key) => fn(obj[key], key));
};

export class Store {
  constructor(options) {
    //getters是有缓存的,内部其实是用computed实现
    this.getters = {};
    const getters = options.getters; //用户传过来的geters,写的是方法,取值的时候是属性
    const computed = {};
    forEach(getters, (fn, key) => {
      computed[key] = () => {
        // 依赖值不变就不会更新
        return fn(this.state);
      };
      Object.defineProperty(this.getters, key, {
        get: () => this._vm[key],// 这里用计算属性包装一层,否则就没有缓存的效果
      });
    });
   //这里的options.state 即为用户new Vuex.Store({state:{}})时传入的state
   //Vuex数据修改后视图可以更新实际上内部就是new了一个vue实例
   //Vue中定义数据,属性名如果是$开头,数据是不会被代理到实例上的,也就是通过this._vm.$$state取值是取不到的
    this._vm = new _Vue({
      data() {
        return {
          $$state: options.state,//$标识表示内部的状态
        };
      },
      computed,
    });
  }
  get state() {
    //可以通过_data访问到
    return this._vm._data.$$state;
  }
}

mutations 实现

export class Store {
  constructor(options) {
    //getters是有缓存的,内部其实是用computed实现
    this.getters = {};
    const getters = options.getters; //用户传过来的geters,写的是方法,取值的时候是属性
    const computed = {};
    forEach(getters, (fn, key) => {
      computed[key] = () => {
        // 依赖值不变就不会更新
        return fn(this.state);
      };
      Object.defineProperty(this.getters, key, {
        get: () => this._vm[key],// 这里用计算属性包装一层,否则就没有缓存的效果
      });
    });
   //这里的options.state 即为用户new Vuex.Store({state:{}})时传入的state
   //Vuex数据修改后视图可以更新实际上内部就是new了一个vue实例
   //Vue中定义数据,属性名如果是$开头,数据是不会被代理到实例上的,也就是通过this._vm.$$state取值是取不到的
    this._vm = new _Vue({
      data() {
        return {
          $$state: options.state,//$标识表示内部的状态
        };
      },
      computed,
    });
    // mutations
    this._mutations = {};
    //这里为上面提到的工具函数
    forEach(options.mutations, (fn, key) => {
      this._mutations[key] = (payload) => fn.call(this, this.state, payload);
    });
  }
  // 这里使用箭头函数,保证解构后this指向
  commit = (type, payload) => {
    this._mutations[type](payload);
  };
  get state() {
    //可以通过_data访问到
    return this._vm._data.$$state;
  }
}

actions 实现同mutations

export class Store {
  constructor(options) {
    //getters是有缓存的,内部其实是用computed实现
    this.getters = {};
    const getters = options.getters; //用户传过来的geters,写的是方法,取值的时候是属性
    const computed = {};
    forEach(getters, (fn, key) => {
      computed[key] = () => {
        // 依赖值不变就不会更新
        return fn(this.state);
      };
      Object.defineProperty(this.getters, key, {
        get: () => this._vm[key],// 这里用计算属性包装一层,否则就没有缓存的效果
      });
    });
   //这里的options.state 即为用户new Vuex.Store({state:{}})时传入的state
   //Vuex数据修改后视图可以更新实际上内部就是new了一个vue实例
   //Vue中定义数据,属性名如果是$开头,数据是不会被代理到实例上的,也就是通过this._vm.$$state取值是取不到的
    this._vm = new _Vue({
      data() {
        return {
          $$state: options.state,//$标识表示内部的状态
        };
      },
      computed,
    });
    // mutations
    this._mutations = {};
    //这里为上面提到的工具函数
    forEach(options.mutations, (fn, key) => {
      this._mutations[key] = (payload) => fn.call(this, this.state, payload);
    });
    this._actions = {};
    forEach(options.actions, (fn, key) => {
      this._actions[key] = (payload) => fn.call(this, this, payload);
    });
  }
  // 这里使用箭头函数,保证解构后this指向
  commit = (type, payload) => {
    this._mutations[type](payload);
  };
  dispatch = (type, payload) => {
    this._actions[type](payload)
  };
  get state() {
    //可以通过_data访问到
    return this._vm._data.$$state;
  }
}

以上就基本实现了一个简易版的vuex。