为Vuex添加同步Action
为什么要添加同步 Action?
在某些操作中,如获取内存中的数据时,需要立即返回对应的值,而 Vuex 的 Action 规定了只能返回一个 Promise,这时,如果我们想获取返回值就需要使用 then 或者 await,代码就会变得不直观,而如果触发 Mutation 再从 State 获取值也是同理,所以如何能让 Action 不是异步的又能保持和 Vuex 的 Action 拥有一样的功能呢?
添加同步 Action
首先我们先看看 Vuex 的 Action 的结构是如何的:
_5const actions = {_5 asyncAction(context, data) {_5 // do soming..._5 }_5};
可以看到,action 中传入了 context 和 data,所以我们添加的同步 action 也需要增加这两个参数,同时将 store 绑定到 action 的 this。
_23const actions = {_23 asyncAction(context, data) {_23 // do soming..._23 }_23};_23_23export const syncActions = {_23 // 同时导出,以便后续的操作_23 syncActin(context, data) {_23 // do soming..._23 return val;_23 }_23};_23_23//..._23_23export default {_23 namespaced: true,_23 state,_23 getters,_23 actions,_23 mutations_23};
在 index.js 导入对应的模块和同步 actions 对象,同时导出修改过的同步 action,用于 mapSyncActions,并为每个同步 action 绑定 this 和注入参数。
_42import note, { syncActions as syncNote } from "./modules/note";_42import { dispatchSync } from "./syncActions";_42_42export const syncActions = {_42 note: syncNote_42};_42_42for (const nKey in syncActions) {_42 let getters = {};_42 for (const gKey of Object.keys(store.getters)) {_42 let k = gKey.split("/");_42 if (k[0] === nKey) {_42 Object.defineProperty(getters, k[1], {_42 get() {_42 return store.getters[gKey];_42 }_42 });_42 }_42 }_42 for (const iKey in syncActions[nKey]) {_42 syncActions[nKey][iKey] = syncActions[nKey][iKey].bind(store, {_42 state: store.state[nKey],_42 rootState: store.state,_42 commit: function (type, payload = null, options = null) {_42 store.commit(nKey + "/" + type, payload, options);_42 }.bind(store),_42 dispatch: function (type, payload = null, options = { root: false }) {_42 let t = options.root ? type : nKey + "/" + type;_42 return store.dispatch(t, payload);_42 }.bind(store),_42 dispatchSync: function (type, payload = null, options = { root: false }) {_42 let t = options.root ? type : nKey + "/" + type;_42 return dispatchSync(t, payload);_42 }.bind(store),_42 rootGetters: store.getters,_42 getters: getters_42 });_42 }_42}_42_42store.syncActions = syncActions;_42store.dispatchSync = dispatchSync;
然后,我们还要实现对应的 dispatch 方法和 mapActions 方法,来实现调用该 action,在 index.js 同级文件夹下添加一个 syncActions.js
_47import { syncActions } from "./index";_47_47function addMethod(object, name, fn) {_47 var old = object[name];_47 object[name] = function () {_47 if (fn.length === arguments.length) {_47 return fn.apply(this, arguments);_47 } else if (typeof old === "function") {_47 return old.apply(this, arguments);_47 }_47 };_47}_47_47const mod = {};_47_47addMethod(mod, "mapSyncActions", (map) => {_47 let fn = {};_47 let namespace = "";_47 let action = "";_47 for (let i = 0; i < map.length; i++) {_47 [namespace, action] = map[i].split("/");_47 if (syncActions[namespace]) {_47 fn[action] = syncActions[namespace][action];_47 }_47 }_47 return fn;_47});_47_47addMethod(mod, "mapSyncActions", (namespace, map) => {_47 let fn = {};_47 for (let i = 0; i < map.length; i++) {_47 if (syncActions[namespace]) {_47 fn[map[i]] = syncActions[namespace][map[i]];_47 }_47 }_47 return fn;_47});_47_47export const mapSyncActions = mod.mapSyncActions;_47export function dispatchSync(type, payload = null) {_47 let namespace = "";_47 let action = "";_47 [namespace, action] = type.split("/");_47 if (syncActions[namespace]) {_47 return syncActions[namespace][action](payload);_47 }_47}
如果要在 Vuex 模块中使用,只需要导入 syncActions.js 然后同 Vuex 的 action 调用一样即可。
_7import { dispatchSync } from "../syncActions";_7_7let info = dispatchSync("note/listOperate", {_7 operate: "get",_7 storage: storage,_7 path: path_7});
若要在组件中使用,只需要同 mapActions 一样使用 mapSyncActions 即可,或者使用 dispatchSync。
_10import { mapSyncActions } from "./store/syncActions";_10_10export default {_10 methods: {_10 ...mapSyncActions("note", ["listOperate"]),_10 fun() {_10 this.$store.dispatchSync("note/listOperate");_10 }_10 }_10};
结语
说实在搞这个其实没啥用,因为用到的机会其实也很小,只是当初我把 XK-Note 重构到 Vuex 时,不想修改太多的代码逻辑搞出来的,本文的实例具体可以查看 XK-Note。
为Vuex添加同步Action
https://blog.ixk.me/post/add-sync-action-for-vuex许可协议
发布于
2019-11-16
本文作者
Otstar Lin
转载或引用本文时请遵守许可协议,注明出处、不得用于商业用途!