【问题标题】:Way to make inheritance in Vuex modules在 Vuex 模块中进行继承的方法
【发布时间】:2018-06-27 21:03:59
【问题描述】:

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

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);
    })
},

而其他Modules中的另一个功能是这样的

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 函数,我需要对这些字段进行变异。但是一直重复是没有意义的……有什么建议吗?

【问题讨论】:

  • 你试过了吗?如果有,发生了什么?
  • 它不起作用。我不知道我怎么能真正处理那个。有什么建议吗?

标签: javascript inheritance vue.js extends vuex


【解决方案1】:

我将可重用的 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
};

【讨论】:

  • 是否有任何理由将endpoint 置于模块状态?我想知道,因为它已经在“(调用 API)”部分的闭包中可用。
  • 我知道,“谢谢”cmets 是不鼓励的,但这是迄今为止我看到的问题的最优雅的答案之一。 :)
【解决方案2】:

开发更多 Erin 的响应,您可以定义一个具有以下共同特征的基类:

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(),
        };
    }
}

您现在可以通过类继承仅扩展/覆盖派生类中需要的部分;例如,如果您需要扩展模块...:

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,
});

【讨论】:

  • 太棒了!我很想看到一个完整的示例项目,例如库存商店。
【解决方案3】:

我根据以下方式找到了状态字段的一些继承:

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

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

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

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

我的消息变异表单 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

【讨论】:

    【解决方案4】:

    这是我所做的:

    首先,我创建了一个mainApi.js,其职责就是与api建立连接

    ma​​inApi.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}`);
        },
    }
    

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

    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 基类的函数和方法都是我们模块的一部分)并使用接收到的数据进行操作。

    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: {}
    
    })
    

    在此示例中,我使用 anotherPromise,因为我需要直接在我的视图中的服务器响应。如果您只想在商店中使用响应,则不需要这些 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')
        }
    }
    

    【讨论】:

      【解决方案5】:

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

      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())
              }
          }
      }
      

      由此我创建了自己的类模块,通过重新定义我想以这种方式自定义的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;
          }
      }
      

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

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

      【讨论】:

        猜你喜欢
        • 2012-05-28
        • 2011-03-10
        • 2019-05-23
        • 2011-10-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多