vuex 缓存字典数据

1,044 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情

背景

开发过程中,系统一般都会维护字典数据。将一个系统中的属性值定义成字典。比如,性别,城市,岗位,学历,名族等。

字典数据的种类很多,系统中每个页面用到字典数据的地方都要,去请求接口,比如A页面中用到的性别这个字典数据,A页面中的一个弹窗也用到了性别数据,打开弹窗的时候就会再次请求这个数据,当需要的字段很多时,就会发起大量的请求字典数据请求。

现在的需求是,只需一次请求,然后将请求的该类型的字典数据缓存起来,下次用的时候先从缓存数据中找,如果有的话就直接用,没有的话再去请求。

刚好使用 vuex 可以轻松的实现上述的需求。

先来复习以下vuex的用法吧

vuex 的 4 个属性 :State, Mutations,Actions,Getters

  • state:我们要把我们需要做状态管理的量放到这里来,然后在后面的操作动它

  • mutation:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation

  • actions:

    action 类似于 mutation,不同在于:

    action 提交的是 mutation,而不是直接变更状态。

    action 中可以写异步

  • getters: 用于存取数据

步骤

1.在项目中创建文件夹 store

store 的结构如下:

  • modules 文件夹中存放不同功能的vuex代码
  • getters.js 汇总 modules 文件夹中的getter
  • index.js 入口文件

2.创建并编写 index.js

main.js中导入import store from './store/index'

index.js:整合modules

import Vue from "vue";
import Vuex from "vuex";
import getters from "./getters";

Vue.use(Vuex);

// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context("./modules", true, /\.js$/);

// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
  // set './app.js' => 'app'
  const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, "$1");
  const value = modulesFiles(modulePath);
  modules[moduleName] = value.default;
  return modules;
}, {});

const store = new Vuex.Store({
  modules,
  getters,
});

export default store;

require.context() 方法创建自己的(模块)上下文,方法有 3 个参数:

  • 要搜索的文件夹目录
  • 是否还应该搜索它的子目录,
  • 以及一个匹配文件的正则表达式。

3.创建并编写 getter.js

getter.js

export default {
  dict: (state) => state.dict.dict,
};

4.创建并编写 dict.js

dict 的数据结构:通过键值对取存储字典。

interface ditc{
   codeName:String
   codeValue:Array
}

每次我们需要字典数据时都从 dict 中去匹配,比如关于性别的字典数据:

sex:[
        {
                label:'男',
                value:'01'
        },
        {
                label:'女',
                value:'02'
        },
]

dict.sex 如果有值就把值取出来,通过 Promise 方法 resolve 出去。如果没有,就去调接口请求数据,拿到数据后,需要做下面两步操作。

1.queryByClaCode()是用来请求后台数据的接口,把拿到的数据存到 vuex 中。

commit("SET_DICT", {
  key: code,
  value: option,
});

2.配置键名,如果缓存中存在返回数据,如果不存在请求后返回,并将数据缓存起来

resolve({ option })

dict.js 的完整代码:

import { queryByClaCode } from "@/apis/system";

const state = {
  dict: {},
};
const mutations = {
  SET_DICT(state, object) {
    let { key, value } = object;
    try {
      state.dict[key] = value;
    } catch (error) {
      console.log(error);
    }
  },
};
const actions = {
  // query
  getDictionary({ commit, state }, code) {
    return new Promise((resolve, reject) => {
      let dict = state.dict;
      if (!dict[code] || (dict[code] && dict[code].length === 0)) {
        //当缓存中没有时去请求
        queryByClaCode(code)
          .then((res) => {
            let option = res.data || [];
            commit("SET_DICT", {
              key: code,
              value: option,
            });
            resolve({ option });
          })
          .catch(() => {
            reject(false);
          });
      } else {
        resolve({ option: dict[code] });
      }
    });
  },
};

export default {
  namespaced: true,
  state,
  mutations,
  actions,
};

5.使用

1.通过 dispatch

// codeName 字典名
this.$store.dispatch("dict/getDictionary", codeName).then((res) => {
  let codeOption = res.option || [];
});

2.通过 mapGetters函数

import {mapGetters} from 'vuex'
computed:{
	...mapGetters([dict['sex']])
}

3.更新字典

this.$store.commit('dict/SET_DICT', {'sex':['m':'男','w':'女']});

总结

算是一个开发中优化的一个小技巧吧,开发的上一个项目中需要大量请求这些字段数据,甚至有的数据可以达到上千条,到此也没什么,就这点数据量也不会造成严重性能影响,只是后来需求变更,需要在表格中编辑这些数据,甚至是批量编辑,表格中一条数据20多个字段有下拉数据,每次编辑状态的切换都会去请求字典数据。导致页面有明显的卡顿,继更换 v-if 为 v-show 等操作后,做个这次优化操作。