在 Vuex 模块中进行继承的方法

Way to make inheritance in Vuex modules

我正在使用 VueJS 和 Vuex 构建我的应用程序,当我有多个模块使用相同的数据字段时,我遇到了这个问题。关于API配置像dat.

getUsers ({ state, commit }) {
    axios.get(urls.API_USER_URL).then( response => {
        let data = response.data;
        parseApi(state, data, 'user');

    }).catch( err => {
        console.log('getUser error: ', err);
    })
},

其他模块中的另一个功能就像

getPosts ({ state, commit }) {
    axios.get(urls.API_POST_URL).then( response => {
        let data = response.data;
        parseApi(state, data, 'posts');

    }).catch( err => {
        console.log('getUser error: ', err);
    })
},

我想知道我是否可以继承我的模块并在其中添加额外的数据字段/函数?

我的每个模块都会有消息和状态字段,我收到这些字段是为了响应我的 API。

export default {
    state : {
        message : "",
        status : 0
    },
    parseApi: function(state, data, property) {
        if (data.hasOwnProperty('message')) {
            state.message = data.message;
        }
        if (data.hasOwnProperty('status')) {
            state.status = data.status;
        }
        if (data.hasOwnProperty(property)) {
            state[property] = data[property];
        }
    }
}

会是这样的。

有没有一种方法可以一次性编写此代码并将其放入我使用的每个模块中?

已编辑:

我什至无法在其中获取此 apiParse 函数,我需要对这些字段进行变异。但是一直重复它是没有意义的...有什么建议吗?

我根据以下内容找出了状态字段的一些继承:

https://vuex.vuejs.org/en/modules.html#namespacing

export default {
    namespaced: true,
    state,
    getters,
    actions,
    mutations,
    modules : {
        apiResponses
    }
}

我在带有命名空间的模块用户之后导出了 apiResponses 模块,接下来我对 posts 做了同样的事情。

命名空间继承了那些消息/状态状态及其变化,我刚刚在我的用户和 post 模块中调用了它们。现在他们正在正常工作。

我的消息变异形式 apiResponses:

[types.SET_MESSAGE] (state, message) {
    state.message = message;
},

在我的用户模块的操作中工作

if (data.hasOwnProperty('message')) {
    commit(types.SET_MESSAGE, data.message);
}

然后在我的组件中我只是调用。

    computed: {
        ...mapGetters({
            user : 'user/user',
            userMessage : 'user/message',
            post: 'post/monitoring',
            postMessage : 'post/message',

        }),
    },

已编辑

我的问题的最后一部分就是这样。

我在 apiResponse 模块中执行了操作

let actions = {
    getResponseParsed({commit}, payload) {
        console.log(payload)
        if (payload.data.hasOwnProperty('message')) {
            commit(types.SET_MESSAGE, payload.data.message);
        }
        if (payload.data.hasOwnProperty('status')) {
            commit(types.SET_STATUS, payload.data.status);
        }
        if (payload.data.hasOwnProperty(payload.property)) {
            commit(payload.mutation, payload.data[payload.property]);
        }
    }
}

然后在我的用户和其他模块中,我这样称呼它:

getUser ({ state, commit, dispatch }) {
    axios.get(urls.API_GET_USER_URL).then( response => {
        let data = response.data;

        dispatch('getResponseParsed', {
            data : data,
            mutation : types.SET_USER,
            property : 'user'
        });

    });
},

最后一件事,我们需要使这个新模块可重用,根据我们需要像组件一样创建它的文档。

export default {
    state() {
        return {
            message : '',
            status : 0,
        }
    },
    getters,
    mutations,
    actions
}

以状态为函数:)

希望其他人也有同样的问题 :D

我将我的可重用 vuex 代码放在小 类 中。例如。

crud.js

export default class {
    constructor ( endpoint ) {
       this.state = {
          endpoint: endpoint,
          meta:     {},
          status:   null,
          known:    [],
          currentId: null,
       };
       this.getters = {
          id: state => id => state.known.find( o => o.id === id )
       };
       this.actions = {
          async store( context, payload ) {
               *(call to API)*
          },
          async update( context, payload ) {
               *(call to API)*
          },
          *...etc*
      };
      this.mutations = {
         STORED(state, item) {
            state.known.push(item);
         },
         *...etc*
      };
   }
}

然后我就可以在我的所有模块中使用它了:

user.module.js

import Crud from '/crud';
var crud = new Crud('/api/users');

const state = {
   ...crud.state,
};
const getters = {
   ...crud.getters,
};
const actions = {
   ...crud.actions,
};
const mutations = {
   ...crud.mutations,
};

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

进一步开发 Erin 的响应,您可以定义一个具有如下共同特征的基础 class:

export default class BaseModule {
    protected state() {
        return {
            isLoading: false,
        };
    };
    protected getters() {
        return {
            isLoading(s) {
                return s.isLoading;
            },
        };
    };
    protected actions() {
        return {};
    };
    protected mutations() {
        return {
            [START_TRANSACTION]: (s) => {
                s.isLoading = true;
            },
            [END_TRANSACTION]: (s) => {
                s.isLoading = false;
            },
        };
    }
    protected modules() {
        return {};
    };

    public getModule = () => {
        return {
            namespaced: true,
            state: this.state(),
            getters: this.getters(),
            actions: this.actions(),
            mutations: this.mutations(),
            modules: this.modules(),
        };
    }
}

您现在可以 extend/override 在派生 class 中只需要您需要的部分,具有 class 继承;例如,如果您需要扩展模块...:[=​​14=]

import BaseModule from './BaseModule';
import rowDensity from '@/store/modules/reusable/rowDensity';

export default class ItemListModule extends BaseModule {  
  protected modules() {
    return {
      ...super.modules(),
      rowDensity,
    };
  };
}

最后,要将它们作为商店中的模块使用,您可以实例化它们并调用 .getModule():

import Vue from 'vue';
import Vuex from 'vuex';
import ItemListModule from './modules/ItemListModule';

Vue.use(Vuex);

const debug = process.env.NODE_ENV !== 'production';

export const MODULE_NAMESPACES = {
  List: 'list',
};

export default new Vuex.Store({
  modules: {
    [MODULE_NAMESPACES.List]: new ItemListModule().getModule(),
  },
  strict: debug,
});

作为个人挑战,我希望能够创建一个纯 ES6 class 来表达这种需求(意味着不允许注释)。因此,我创建了一个 AbstractModule class 定义高级操作:

export default class AbstractModule {
    constructor(namespaced = true) {
        this.namespaced = namespaced;
    }

    _state () {
        return {}
    }

    _mutations () {
        return {}
    }

    _actions () {
        return {}
    }

    _getters () {
        return {}
    }

    static _exportMethodList (instance, methods) {
        let result = {};
        // Process methods when specified as array
        if (Array.isArray(methods)) {
            for (let method of methods) {
                if (typeof method === 'string') {
                    result[method] = instance[method].bind(instance);
                }

                if (typeof method === 'function') {
                    result[method.name] = method.bind(instance);
                }

                // else ignore
            }
        }

        // Process methods when specified as plain object
        if (typeof methods === "object") {
            for (const [name, method] of Object.entries(methods)) {
                if (typeof method === 'string') {
                    result[name] = instance[method].bind(instance);
                }

                if (typeof method === 'function') {
                    result[name] = method.bind(instance);
                }
            }
        }

        // Process methods when specified as single string
        if (typeof methods === 'string') {
            result[name] = instance[methods].bind(instance);
        }

        // Process methods when specified as single callback
        if (typeof methods === 'function') {
            result[name] = methods.bind(instance);
        }

        return result;
    }

    static module() {
        let instance = new this();
        console.log(instance);

        return {
            namespaced: instance.namespaced,
            state: instance._state(),
            mutations: AbstractModule._exportMethodList(instance, instance._mutations()),
            actions: AbstractModule._exportMethodList(instance, instance._actions()),
            getters: AbstractModule._exportMethodList(instance, instance._getters())
        }
    }
}

由此我创建了自己的 class 模块 通过重新定义 parent 方法,我想以这种方式自定义:

export default class QuestionModule extends AbstractModule{
    constructor(question) {
        super();
        this.question = question;
    }

    selectLine (state, line) {
        this.question.selectLine(line);
    }

    unselectLine (state, line) {
        this.question.unselectLine(line);
    }

    submit ({ state, commit, rootState }) {
        /** API call */
    }

    _state () {
        return this.question;
    }

    _mutations () {
        return [this.selectLine, this.unselectLine, this.validate];
    }

    _actions () {
        return this.submit;
    }
}

最后一步是将我的 class 模块声明到 Vuex 存储中(通过调用 module 静态方法):

const store = new Vuex.Store({
  modules: {
      question: QuestionModule.module()
  },
  strict: process.env.NODE_ENV !== 'production'
});

这是我所做的:

首先,我创建了一个mainApi.js,它的职责只是与api

建立联系

mainApi.js

import axios from "@/plugins/axios";

export default {
    get(url ,id){
        return axios.get(`/${url}/${id}`);
    },
    getAll(url, filter) {
        return axios.get(`/${url}`, {params: {...filter}});
    },
    create(url ,teBeCreated){
        return axios.post(`/${url}`, teBeCreated);
    },
    update(url ,toBeUpdated){
        return axios.put(`/${url}/${toBeUpdated.oid}`, toBeUpdated);
    },
    delete(url ,id){
        return axios.delete(`/${url}/${id}`);
    },
}

其次:我写了一个基础class来定义存储数据所需的函数。那么这个class可以被其他商店模块继承。

gate.js

import mainApi from '@/api/main'
import store from '@/store'

export default class {

  constructor() {

    this.state = {
        view: null,
        list: [],
    };

    this.getters = {
        view: (state) => state.view,
        list: (state) => state.list,
    }

    this.mutations = {
        SET_VIEW(state, payload) {
            state.view = payload;
        },
        SET_LIST(state, payload) {
            state.list = payload;
        },
        UN_SET_VIEW(state) {
            state.view = null;
        },
        UN_SET_LIST(state) {
            state.list = [];
        },
    }

    this.actions = {
        get({ commit }, { url, id }) {
            return new Promise((resolve, reject) => {
                mainApi.get(url, id)
                    .then(response => {
                        commit('SET_VIEW', response.data.data);
                        resolve(response)
                    })
                    .catch(error => {
                        console.log("error in get method in gate store: ", error);
                        commit('UN_SET_VIEW');
                        reject(error)
                    })
            });
        },
        getAll({ commit }, { url, filter }) {
            return new Promise((resolve, reject) => {
                mainApi.getAll(url, filter)
                    .then(response => {
                        commit('SET_LIST', response.data.data);
                        resolve(response)
                    })
                    .catch(error => {
                        console.log("error in getAll method in gate store: ", error);
                        commit('UN_SET_LIST');
                        reject(error)
                    })
            });
        },
        create({ commit }, { url, params }) {
            return new Promise((resolve, reject) => {
                mainApi.create(url, params)
                    .then(response => {
                        resolve(response)
                    })
                    .catch(error => {
                        console.log("error in create method in gate store: ", error);
                        reject(error)
                    });
            });
        },
        update({ commit }, { url, params }) {
            return new Promise((resolve, reject) => {
                mainApi.update(url, params)
                    .then(response => {
                        resolve(response)
                    })
                    .catch(error => {
                        console.log("error in update method in gate store: ", error);
                        reject(error)
                    })
            })
        },
        delete({ commit }, { url, id }) {
            return new Promise((resolve, reject) => {
                mainApi.delete(url, id)
                    .then(response => {
                        resolve(response);
                    })
                    .catch(error => {
                        console.log("error in delete method in gate store: ", error);
                        reject(error)
                    })
            });
        },
    }
}

第三:现在,我们可以根据需要定义任意多个单独的商店模块。正如你在下面看到的,在每个模块中,我们只需要从视图中获取数据并将它们传递给 mainApi(gate.js base class 的函数和方法都是我们模块的一部分)并进行操作收到数据。

someStore.js

import Gate from '@/store/modules/gate'

let gate = new Gate();
const url = 'customUrl'

const gateStates = { ...gate.state }
const gateGetters = { ...gate.getters }
const gateMutations = { ...gate.mutations }

const state = {
    ...gateStates,
};
const getters = {
    ...gateGetters,
};
const mutations = {
    ...gateMutations,
};

const actions = {
    get: ({ commit }, id) => gate.actions.get({ commit }, { url, id }),
    getAll: ({ commit }) => gate.actions.getAll({ commit }, {url, filter: {}}),
    create: ({ commit }, params) => gate.actions.create({ commit }, { url, params }),
    update: ({ commit }, params) => gate.actions.update({ commit }, { url, params }),
    delete: ({ commit }, id) => gate.actions.delete({ commit }, { url, id })
};

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

最后我们应该导入我们的模块并将它们定义为“vuex 存储模块”所以:

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import someModule from './modules/someModule'

Vue.use(Vuex)

export default new Vuex.Store({

    state: {},

    mutations: {},

    actions: {},

    modules: {
        someModule
    },

    plugins: {}

})

在这个例子中,我使用了另一个Promise,因为我需要直接在我的视图中得到服务器响应。如果你只想在你的商店中使用响应,则不需要这些 Promise,它们应该如下删除:

gate.js 改变这个

get({ commit }, { url, id }) {
    return new Promise((resolve, reject) => {
        mainApi.get(url, id)
            .then(response => {
                commit('SET_VIEW', response.data.data);
                resolve(response)
            })
            .catch(error => {
                commit('UN_SET_VIEW');
                console.log("error in getOne method in gate store: ", error);
                reject(error)
            })
    });
},

至此

get({ commit }, { url, id }) {
    mainApi.get(url, id)
        .then(response => {
            commit('SET_VIEW', response.data.data);
        })
        .catch(error => {
            commit('UN_SET_VIEW');
            console.log("error in getOne method in gate store: ", error);
        })
},

这样,你在每个模块中都有 listview 参数,并且可以在你的视图中轻松调用它们:

someView.vue

created() {
    store.dispatch('someModule/get', this.$route.params.id)
}

computed: {
    view() {
        return store.getters('someModule/view')
    }
}