Vuex两个知识点 - 命名空间namespaced与插件plugins

621 阅读2分钟

命名空间-namespaced

在前端的知识体系中,命名空间的概念或许你或多或少都有听说过,本章讲解一下 Vuex 中的命名空间的作用。

相信各位对 Vuex 都很熟了,我们经常拿它来作数据共享,但由于 Vuex 使用的是单一的状态管理模式, 所有状态都会挂载到一个对象(store)上。但随着我们项目中业务的增多,store 对象可能变得非常庞大和臃肿,致使我们的维护是非常复杂和麻烦的。

因此,Vuex 出现了模块的概念,它允许我们对 store 对象进行切割,划分成一个一个小模块,每个模块都拥有自己的 statemutationsactionsgetters。在默认情况下,模块内部的 mutationsactionsgetters全局注册。

什么意思呢?我们来看看下面的 user.js 模块:

// store/modules/user.js
export default {
  state: {
    name: '橙某人',
  },
  mutations: {
    setName(state, newName) {
      state.name = newName;
    }
  },
  actions: {
    updateName({ commit }, newName) {
      setTimeout(() => {
        commit('setName', newName)
      }, 3000)
    }
  },
  getters: {
    getName: (state) => state.name
  }
}

引入:

// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {},
  mutations: {
   setName() {
     console.log('俺也会被触发-setName');
   }
  },
  actions: {},
  getters: {},
  modules: { user }
})

在具体业务中使用:

this.$store.commit('setName', 'ydydydq');
// this.$store.dispatch('updateName', 'ydydyd');
// let name = this.$store.getters.getName;

image.png

上面的例子中,你会发现两个 setName() 方法都被触发了,这并不是我们想看到的,当我们项目模块很多时,就容易发现重名事件,这种场景就非常容易发生!

那我们如何来解决这个问题呢?Vuex 引入命名空间的概念,我们仅仅需要在模块中添加 namespaced 属性即可:

// store/modules/user.js
export default {
  namespaced: true, // 模块开启命名空间
  state: {
    name: '橙某人',
  },
  mutations: {
    setName(state, newName) {
      state.name = newName;
    }
  },
  ...
}

具体业务使用:

this.$store.commit('user/setName', 'ydydydq');
// this.$store.dispatch('user/updateName', 'ydydyd');
// let name = this.$store.getters['user/getName'];

image.png

是不是非常的简单?(✪ω✪) 当然有个需要注意的点,就是模块中的 state 默认嵌套了命名空间的, 所以开不开启模块的命名空间对 state 是没有影响的。

let name = this.$store.state.user.name;

插件-plugins

说起 Vuex 可能我们首先都会记得它有五个核心概念,statemutationsactionsgettersmodules,但其实它还有一些内容也是挺重要,像 map 辅助函数、注册动态模块(registerModule)和插件(plugins)等等。

接下来,我们就来看看 plugins 的使用方式和作用场景。

它的使用很简单:

// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import indexPlugin from './plugins/index'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {},
  mutations: {},
  actions: {},
  getters: {},
  modules: {},
  plugins: [indexPlugin]
})

Vuex 的插件就是一个函数,它接收 store 作为唯一参数:

// store/plugins/index
export default function createIndexPlugin(store) {
  console.log(store); // store为整个Vuex实例, 会在初始化的时候调用
  store.subscribe((mutation, state) => {
    // 每次 mutation 之后调用, 也就是你每次调用 this.$store.commit() 会触发
    console.log(mutation, state);
  })
}

image.png

以上就是它的基本使用,至于它的作用场景,小编总结这三点内容。

数据同步

// socket是与服务端建立长链接实例
const plugin = createWebSocketPlugin(socket);
const store = new Vuex.Store({
  state,
  mutations,
  plugins: [plugin]
})

export default function createWebSocketPlugin (socket) {
  return store => {
    // 服务端通知时触发
    socket.on('data', data => {
      store.commit('receiveData', data) // 同步到本地
    })
    store.subscribe(mutation => {
      if (mutation.type === 'UPDATE_DATA') {
        socket.emit('update', mutation.payload) // 同步到服务端
      }
    })
  }
}

生成快照

const myPluginWithSnapshot = store => {
  // 把初始化的state进行一次深拷贝
  let prevState = _.cloneDeep(store.state)
  
  store.subscribe((mutation, state) => {
    let nextState = _.cloneDeep(state)

    // 比较 prevState 和 nextState...

    // 保存状态,用于下一次 mutation
    prevState = nextState
  })
}

日志上报

import {logAPI} from '@/api/logs';

export default function createLogsPlugins(store) {
  store.subscribe((mutations, state) => {
     logAPI(mutations.type, mutations.payload); // 上报接口
  })
}

上面三种使用场景,前两种来源官方的 DEMO,后一种是小编项目中使用到情况,大家看情况使用吧。(~ ̄▽ ̄)~




至此,本篇文章就写完啦,撒花撒花。

image.png

希望本文对你有所帮助,如有任何疑问,期待你的留言哦。
老样子,点赞+评论=你会了,收藏=你精通了。