学习《玩转 Vue3 全家桶》之手写 Vuex

627 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

本文源代码来自极客时间的《玩转 Vue3 全家桶》,对详细内容感兴趣可去官网购买学习

1. 知识储备

1.1 Vuex 基础知识

首先需要去官网熟悉一下基本概念。Vuex 是集中式状态管理工具。它和全局对象有两点区别,第一点是 Vuex 中的数据是响应式的,即数据变动视图也会跟着变动,第二点是 Vuex 中的数据必须显示提交才可以改变,也就是说修改数据的时候都需要显示调用提供的 commit 方法。它的核心概念有4个,其中 state 用来存放数据,getter 用来获取数据(类似于 Vue 的计算属性),mutation 用来修改数据(这个是修改数据的唯一方法),action 用来异步修改数据(注意,它需要通过 mutation 修改数据)

1.2 Vue 基础知识

Vuex 作为全局管理插件,需要实现跨多个组件通信的场景,所以需要使用 provide/inject 方法。Vue 和 Vuex 链接是通过插件进行的,Vuex 在实现的时候需要有 install 方法,而 Vue 通过 use 方法调用插件中的 install 方法。

2. 源码分析

2.1 输入

该模块引入 inject,reactive,computed 三个方法,其中 inject 用于跨组件使用对象,这里获取到的是 new store 后生成的实例;reactive 用于将 state 中的数据变成响应式的;computed 用于 getter 获取 state 中的数据并保持响应式。

2.2 输出

该模块输出 useStore 和 createStore 两个方法,其中 createStore 方法可以将参数中的 state 变成响应式的,getters 响应式获取 state 中的数据并且支持多个方法,另外还支持 commit 和 dispath

2.3 补充

commit 方法会直接存在于 new Store 创建的实例中,这个不同于 dispatch 方法,它只存在于 Store 的实例对象中,这个是实例属性的新写法,可以参考 ES6入门

3. 源码

import { inject, reactive, computed } from "vue";

const STORE_KEY = "__store__";

// 组件中使用的时候调用
function useStore() {
  return inject(STORE_KEY);
}

// 使用 app.use 方法的时候调用
function createStore(options) {
  return new Store(options);
}

class Store {
  constructor(options) {
    this.$options = options;
    this._state = reactive({
      data: options.state(),
    });
    this._mutations = options.mutations;
    this._actions = options.actions;
    this.getters = {};

    // 遍历 options.getters 中的所有方法,然后放到 getters 中并使用 computed 方法保持响应性
    Object.keys(options.getters).forEach((name) => {
      const fn = options.getters[name];
      this.getters[name] = computed(() => fn(this.state));
    });
  }
  // store.state 的时候获取 data
  get state() {
    return this._state.data;
  }
  // 如果有对应的方法,则调用该方法
  commit = (type, payload) => {
    const entry = this._mutations[type];
    entry && entry(this.state, payload);
  };
  dispatch(type, payload) {
    const entry = this._actions[type];
    return entry && entry(this, payload);
  }
  install(app) {
    app.provide(STORE_KEY, this);
  }
}
export { createStore, useStore };

4. 总结

通过学习手写 Vuex 的代码可以加深对官网文档的理解,同时注意平常使用的时候需要保持响应性,并且只通过 commit 方法进行显示修改数据。