【Vue 故地重游】02.Vuex 篇

345 阅读1分钟

写在前面

Vuex用了那么久了,一直有思考是如何工作的,
今天从 使用层面原理实现 探究 Vuex 如何实现的 状态管理

基本使用

  1. 使用 Vuex 插件
// 1.使用Vuex插件
Vue.use(Vuex);
  1. 创建 store 实例
// 2.创建store实例
new Vuex.Store({
  state: {
    counter: 0,
  },
  mutations: {
    add(state) {
      state.counter++;
    },
  },
  actions: {
    add({ commit }) {
      setTimeout(() => {
        commit('add');
      }, 1000);
    },
  },
  getters: {
    doubleCounter(state) {
      return state.counter * 2;
    },
  },
});
  1. 配置到 options 中
// 3.配置到options中
new Vue({
  // ...其他options
  router,
  render: h => h(App),
}).$mount('#app');

问题

  1. 为什么要先注册插件:Vue.use(Vuex),注册插件都做了那些事情?
  2. new Vuex.Store(...)做了哪些事情,为什么 state 可以响应式变化?
  3. mutations参数中的state从哪里来
  4. actions参数中解构出了commit,commit是什么,从哪里来?

原理探究

state如何做到响应式

在研究VueRouter源码时专门深入了解了用Vue做响应式的几种方式

源码中这样操作

store._vm = new Vue({
  data: {
    $$state: state,
  },
});

Vue响应式模块对于$$开头的属性,不代理到Vue上面,因此 vue 实例 不能直接访问到$$开头的属性,起到了保护变量的作用,只允许通过actionsmutations来更新state

getters 的 原理

getters在使用的时候,是不是就已经发现和 Vuecomputed很像了,没错,Vuex内部对于getters的实现同样是借助了computed, 而computed为何物?其实只是把我们写的computed函数经过简单包装后赋值给Object.defineProperty中第三个参数的get方法, 源码中的操作也很简单,将getters简单处理后,直接赋值给new Vuecomputed属性即可

源码在这里

核心代码其实就是这样

const computed = {};

Object.keys(this.getters).forEach(key => {
  const fn = this.getters[key];

  computed[key] = () => fn(this.state);

  // 将getters中属性的获取代理到vue
  Object.defineProperty(this.getters, key, {
    get: () => this._vm[key],
  });
});
store._vm = new Vue({
  // ... state: {$$state: state}
  computed,
});

mutation 和 actions

这部分没有太过于复杂

核心实现如下

  commit(type, payload) {
    const entry = this._mutations[type];
    if (!entry) {
      console.error('unkown mutation type');
    }

    entry(this.state, payload);
  }

  dispatch(type, payload) {
    const entry = this._actions[type];
    if (!entry) {
      console.error('unkown action type');
    }

    entry(this, payload);
  }

思考与总结

  1. 我对于Vuex的理解

    通过源码,我所理解的Vuex,实际上也是一个全局都可以访问的Vue实例,
    区别是

    1. 这个实例的 响应式 data 要通过 state 访问,
    2. 其修改方式变为 actionsmutations
  2. store中的数据可以直接被修改吗?

    可以,并且还是响应式变化,但项目变大时将变得很难维护,无法做变化监测、日志记录、状态持久化等中间件的开发

  3. actions接收的第一个参数

    第一个参数是store上下文,可以获取到commit,dispatch,state,getters所有内容

  4. Vuedata$$XXXX的区别

    $$XX将不会被Vue代理到this,直接通过this.$$XX无法获取,但是可以通过_data获取,这部分会在 Vue源码 中详细探究