Using vuex+mixin to optimize the access scheme of data dictionary

1. Problem description

In Vue or React projects, we often encounter problems such as the data dictionary of the drop-down box. The data dictionary is obtained when the page is created, and then parsed and displayed.
When different pages use the same data dictionary or the page is opened repeatedly, they will send the same request many times, which will cause a waste of time and performance.
The analysis of data dictionary has high repetition rate and unified mode in the page. There are a large number of repeated codes in each page, which is very inconsistent with the idea of code reuse. We can use "mixing" to improve the code reuse rate.

In short, we need to achieve two points:
1. Save the requested data dictionary and don't send back-end request when using it next time
2. Simplify the operation process of the page code. The page directly obtains the results and uses them, and no longer cares about the process

2. Solution

Use vuex Store to store the data dictionary data
Use mixin to improve code reuse. Mixin can be used to reuse component content more efficiently

The configuration and use of vuex are not introduced here. Vuex is configured in the default project, and mixin is briefly introduced below

Official documents:
By creating Vue components, we can extract the repeated parts of the interface together with its functions into reusable code segments. This alone can make our application go far in maintainability and flexibility. However, our experience has proved that this alone may not be enough, especially when your application becomes very large - think of hundreds of components. When dealing with such large applications, sharing and reusing code becomes particularly important.
Mixin provides a very flexible way to distribute reusable functionality in Vue components. A mixed object can contain any component option. When a component uses mixed objects, the options of all mixed objects will be "mixed" into the options of the component itself.

Document address: https://v3.cn.vuejs.org/guide/mixins.html

Global blending is more convenient. We don't need to declare it in sub components. Global blending will affect the instance of each component, so we need to be careful when using it; In this way, after global mixing, we can directly use this. Com in the component Variable / method to call the variable / method of mixin mixed object;

mixin combines with the objects and methods in the component after introducing the component, which is equivalent to extending the objects and methods of the parent component. It can be understood as forming a new component, which is a little similar to inheritance in java

After the introduction, start the operation. First create the following files:
mixin/metaDataFactoryMixin.js
store/modules/app.js

import store from '@/store'

/**
 * Set custom attribute metaDataType: used to declare the dictionary table used in the definition component
 *
 * The dictionary table declared in the metaDataType can be used directly through metaData and metaDataMapper
 *
 * @author liaoyuxing
 * @date 2021-06-08
 */
const metaDataFactoryMixin = {
  created() {
    let metaDataType = this.$options.metaDataType || null
    if (metaDataType) {
      metaDataType = Object.prototype.toString.call(metaDataType) === '[object Array]' ? metaDataType : [metaDataType]
      metaDataType = metaDataType.map((item) => item.trim())
      localStorage.setItem('metaDataType', JSON.stringify(metaDataType))
      store.dispatch('app/registerMetaDataItems', metaDataType)
    }
  },
  computed: {
    metaData() {
      return store.getters.metaData
    }
  },
  methods: {
    metaDataMapper(key) {
      if (Array.isArray(key)) {
        let all = key.reduce((result, item) => {
          result = Object.assign(result, store.getters.metaDataMap(item) || {})
          console.log('result', result)
          return result
        }, {})
        return all
      }
      return store.getters.metaDataMap(key)
    },
    metaDataFilter(params) {
      return store.getters.filterMetaData(params)
    }
  }
}
export {
  metaDataFactoryMixin
}

import Cookies from 'js-cookie'
import Vue from 'vue'
// Interface to get dictionary value
import { getDictsList } from '@/api/system/dict/data'

const state = {
  metaData: {}
}

const mutations = {
  ADD_META_DATA_ITEMS: (state, items) => {
    Object.keys(items).forEach((key) => {
      let value = items[key].map((item) => {
        let { dictCode, dictValue, dictLabel } = item
        return { dictCode, dictValue, dictLabel }
      })
      Vue.set(state.metaData, key, value)
    })
  }
}

const actions = {
  registerMetaDataItems({ commit, state }, items) {
    let types = items.filter((item) => !state.metaData[item])
    if (types && types.length) {
      getDictsList(types.join(',')).then((response) => {
        commit('ADD_META_DATA_ITEMS', response.data)
      })
    }
  }
}

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

Note here the store The address of the dispatch is' app/registerMetaDataItems'
The corresponding is app Path to enable namespace option in JS

export default {
  namespaced: true
}

When the namespace option is off, the corresponding path should be 'registerMetaDataItems'

Next, register the two files
Add app in store/index js

import Vue from 'vue'
import Vuex from 'vuex'
import app from './modules/app'
import getters from './getters'

Vue.use(Vuex)

const store = new Vuex.Store({
  modules: {
    app,
    settings
  },
  getters
})

export default store

Add metaDataFactoryMixin to main for global blending

// Mixed dictionary method
import {metaDataFactoryMixin} from './mixin/metaDataFactoryMixin'
...
Vue.mixin(metaDataFactoryMixin);

Add dictionary acquisition and parsing methods in store/getters

  metaData: (state, getters) => {
    return state.app.metaData || {}
  },
  filterMetaData: (state, getters) => {
    return (params) => {
      if (typeof params === 'object') {
        let metaData = getters.metaData[params.key] || []
        return metaData.filter((item) => params.filter.some(key => key === item.dictLabel))
      } else {
        return getters.metaData[params] || []
      }
    }
  },
  // Dictionary data
  metaDataMap: (state, getters) => {
    return (key) => {
      let sourceMap = {}
      if (getters.filterMetaData(key)) {
        getters.filterMetaData(key).forEach((item) => {
          sourceMap[item.dictValue] = item.dictLabel
        })
      }
      return sourceMap
    }
  },

Completion of construction
Let's get started
Let's see what changes need to be made in the component:
1. Declare the dictionary to be used on the page

2. Add a parameter to the table to indicate that a dictionary is used, and the modification type is Map

3. Add the judgment that the type is Map. When it is a dictionary, parse it

Change the above code to ↓


Next, verify the results

OK, the display is successful

Similarly, the drop-down box in the page can also use this method
Next, try the use of the drop-down box
Change the parsing metaDataMapper to metaData

Summary:
Through Mixin global blending, we can use metaDataMapper and metaData methods in any component to obtain the dictionary list and value. If we use metaDataType to declare the dictionary to be used in the component, we will automatically judge whether there is cache in the Store and send a request to the backend dynamically.
In short, we don't need to care about the process. We just need the component to declare the required dictionary using metaDataType, and then use metaDataMapper and metaData to obtain the dictionary

Statement:

export default {
  name: 'MiningExecutionTableView',
  metaDataType: ['sys_approve_status'],
  data() {
  ...

use:

// The return value is the dictionary list
metaData['sys_approve_status']
// The return value is approved
metaDataMapper('sys_approve_status')['1']

Keywords: Vue

Added by rach123 on Mon, 31 Jan 2022 07:09:46 +0200