Talk is cheap. Show me your code

结合 Vue.observable 写一个简易 Vuex

作为 Vue 全家桶的一员,Vuex 的重要性不言而喻,不管是用来管理状态,还是封装 Controler 都很好用

不过在一些体量较小的项目中,为了几个简单的状态或者处理函数而引入 Vuex,就像是高射炮打蚊子,大材小用了

这时候就可以模拟 Vuex,自己写一个简单的 Store, 用来管理状态并实时更新数据

 

 

一、构造函数

模拟 Vuex 的结构,创建一个 Class

export default class Store {
  constructor({ states, actions, mutations }) {
    // 状态
    this.states = states || {};
    // 异步函数
    this.actions = actions || {};
    // 同步函数
    this.mutations = mutations || {};
  }
  // 调用 mutations 中的同步函数
  commit = (fun, params) => {};
  // 调用 actions 中的异步函数
  dispatch = (fun, params) => {};
  // 更新 states 的状态
  update = (key, value) => {};
}

 

然后实例化一个 Store

import Store from './store';

import states from './states';
import actions from './actions';
import mutations from './mutations';

const store = new Store({
  states,
  actions,
  mutations,
});

export default store;

 

然后挂到 vue 的原型上,通过 vue.$store 的方式使用,一个高仿 vuex 的架子就搭好了

// 在 main.js 中引入 Store
import store from './store/index';
Vue.prototype.$store = store;

 

 

二、实现操作函数(commit、dispatch、update

在 Vuex 中,如果需要更新 state 中的状态,需要通过 commit 调用 mutations 中的方法

而 mutations 的方法都具备一个默认的参数 state,因此 commit 方法可以这么写:

// 向 mutations 中的传入固定参数 state
commit = (fun, params) => {
  this.mutations[fun](this.states, params);
};

 

不过由于一些历史遗留问题,我习惯用 this.states 的方式获取 state(这个习惯不好),所以改成了这样:

  commit = (fun, params) => {
    if (fun) {
      this.mutations[fun].call(this, params);
    } else {
      return false;
    }
  };

类似的 actions 和 update 可以参考 commit 的写法

 

 

三、响应式对象

目前的 store 有一个致命的问题:state 更新之后并不会即时渲染到视图层

这时候 Vue 2.6.0 新增的 observable() 就派上用场了

 

如果将一个对象作为入参传给 Vue.observable() ,经过处理之后,这个对象在 Vue 内就可以实时更新

其返回值可以直接用于 render 和 computed 中,并且会在发生改变时触发相应的更新

 

于是 Store 的构造函数需要改一改:

  constructor({ states, actions, mutations }) {
    // 状态
    this.states = Vue.observable(states || {});
    // 异步函数
    this.actions = Vue.observable(actions || {});
    // 同步函数
    this.mutations = Vue.observable(mutations || {});
  }

 

⚠️注意:

假如对象 obj 经过 observable() 处理之后,赋值给了新对象 new_obj

在 Vue 2.x 中,直接修改 obj 也会触发 new_obj 的更新

但在 Vue 3.x 中,由于响应机制的变更,只有修改 new_obj 才能触发视图层的更新

所以在使用 observable() 的时候,最好始终操作使用 observable() 处理后的 new_obj

 

 

四、简单用用

超低配的 Vuex 已经写好了,上面已经把 store 挂到 Vue 的原型上,所以可以直接使用

假如 state 中已经存在一个状态 name,在组件中可以通过 computed 去获取

computed: {
    name() {
      return this.$store.states.name;
    },
}

如果需要修改状态,可以通过 $store.update()

methods: {
    updateName(val) {
        this.$store.update('name', val);
    }  
}

或者使用 $store.commit() 调用 mutations 中的方法

methods: {
    commitName(val) {
        this.$store.commit('handleNameChange', val);
    }  
}

大功告成~

posted @ 2019-09-10 14:46  Wise.Wrong  阅读(2997)  评论(0编辑  收藏  举报