petervmeijgaard/vue-2-boilerplate

Vuex structure without code duplications

roquie opened this issue · 2 comments

Hi! I think this question excites many users and maybe it is worth adding to boilerplate as example code.

Vuex based on global state and if you want to use form validation (server side) and API pagination your should duplicate state object for any CRUD operation.

So, for example how use pagination with vuex:

// src/store/modules/position/actions.js
import Transformer from '@/transformers/PositionTransformer';
import PositionProxy from '@/proxies/PositionProxy';
import _ from 'lodash';

export const all = ({ commit }, payload) => {
  const page = _.get(payload, 'page', 1);
  new PositionProxy(payload)
    .setParameters({ page, per_page: 5 }).all().then((response) => {
      commit('ALL', Transformer.fetchCollection(response.data));
      commit('PAGINATE', Transformer.paginate(response.meta.pagination));
    });
};

export const create = ({ commit }, payload) => {
  new PositionProxy().create(payload).then((response) => {
    commit('ACTION_MESSAGE', response.message, { root: true });
  }).catch((response) => {
    if (response.status === 422) {
      commit('VALIDATION', response.data.error.validation);
    }
  });
};

export default {
  all,
  create,
};

// src/store/modules/position/mutations.js
export default {
  ['PAGINATE'](state, pagination) {
    state.pagination = pagination;
  },
  ['ALL'](state, items) {
    //console.log(items);
    state.all = items;
  },
  ['VALIDATION'](state, array) {
    state.validation = array;
  },
};

// src/store/modules/position/state.js
export default {
  all: [],
  pagination: {
    total: 0,
    perPage: 5,
    currentPage: 1,
    totalPages: 1,
    links: []
  },
  validation: []
};

// getters.js and index.js like as boilerplate

Position is a CRUD object which have a two standard things: pagination for list all items in table and server side validation .

If u want add more CRUD object this things will be same and always will be duplicate. Because state should be unique for any object. If pagination will become global state, multiple tables will be works together on the one page. Same situation with validation, if use global validation state for any form.

Okay, I can merge object to prevent duplicate for vuex module files. But what do with duplications in actions of create/update/delete actions where I should handle validation? This part:

//...
  }).catch((response) => {
    if (response.status === 422) {
      commit('VALIDATION', response.data.error.validation);
    }
  });

Maybe your know how to solve this problem? How to put it in a common place (commit() allow only in action callback)?

I think you can add to Axios.interceptors.response to commit an action when the status is 422, similar to how the boilerplate manages a 401. That is, if you don't mind having a global error state.

I think this would clutter Vuex a bit too much for my preference. If you come up with a pull-request, I'd take it in consideration again