Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to manually add getters/mutations to a Vuex store, after it's already created?

I'm trying to add new variables, getters and mutations in the 'created' lifecycle hook in one of my Vuejs components. The variables work fine. But with getters/mutations, it seems it's not as easy as adding new functions to the vuex store object. The problem I'm trying to solve is creating "shared" reusable components.

Here's the component:

<template>
  <div>
    <h2 class="headline">Number of items:</h2>
    <v-select
      :items="limits"
      item-value="value"
      item-text="text"
      label="Select"
      v-model="selected_limit"/>
  </div>
</template>

<script>
  import {selectLimitComponentVariables} from './index';
  import {selectLimitComponentGetters} from './getters';
  import {selectLimitComponentMutations} from './mutations';

  export default {
    created: function () {
      // Add the variables
      Object.assign(this.$store.state[this.ns], selectLimitComponentVariables(this.var_prefix));
      // Add the getters
      Object.assign(this.$store.getters, selectLimitComponentGetters(this.ns, this.var_prefix));
      // Add the mutations
      Object.assign(this.$store._mutations, selectLimitComponentMutations(this.ns, this.var_prefix));
    },
    name: 'SelectLimitComponent',
    props: {
      ns: {
        type: String,
        default: null
      },
      var_prefix: {
        type: String,
        default: ''
      }
    },
    computed: {
      selected_limit: {
        get () {
          return this.$store.state[this.ns].selected_limit;
        },
        set (value) {
          this.$store.commit(`${this.ns}/update${this.var_prefix}selected_limit`, value)
        }
      },
      limits: {
        get() {
          return this.$store.state[this.ns].limits;
        }
      }
    }
  }
</script>

And here are the imported functions. selectLimitComponentVariables:

export const selectLimitComponentVariables = function (prefix) {
  return {
    [`${prefix}selected_limit`]: '100',
    [`${prefix}limits`]: [
      {'text': '10', 'value': '10'},
      {'text': '50', 'value': '50'},
      {'text': '100', 'value': '100'},
      {'text': '250', 'value': '250'},
      {'text': 'No limit', 'value': '-1'}]}
};

selectLimitComponentGetters:

export const selectLimitComponentGetters = function(namespace, prefix){
  return {
    [`${namespace}/${prefix}selected_limit`]: state => state[`${prefix}selected_limit`]
  }
};

selectLimitComponentMutations:

export const selectLimitComponentMutations = function (namespace, prefix){
  return {
    [`${namespace}/update${prefix}selected_limit`]: (state, newLimit) => state[`${prefix}selected_limit`] = newLimit
  }
};

Is there a way to manually add or register new getters/mutations, after the vuex store is created?

like image 886
Andriy Stolyar Avatar asked Oct 20 '25 12:10

Andriy Stolyar


2 Answers

It's better to use store.registerModule feature of vuex to dynamically add new modules to vuex

this.$store.registerModule(`${this.ns}selected_limit`, {
  state: selectLimitComponentVariables...,
  getters: selectLimitComponentGetters...,
  mutations: selectLimitComponentMutations...,
  namespaced: true
})

You can check official document in Dynamic Module Registration section of https://vuex.vuejs.org/en/modules.html

like image 173
ittus Avatar answered Oct 23 '25 02:10

ittus


It looks like what you're trying to do is have per-component Vuex state.

If you modify the Vuex schema at random like that, it would make it very difficult to manage the separation of state (you're just monkey-patching the root Vuex state).

Here's another approach. You could create a separate Vuex module and register it dynamically in the beforeCreate hook of your component.

Vue.use(Vuex);

const HomeModule = {
  namespaced: true,
  state() {
    return {
      count: 0,
    };
  },
  mutations: {
    increment(state) {
      state.count++;
    },
  },
};

const ns = 'home';

Vue.component('home', {
  template: '<div><button @click="increment">+</button> {{ count }}</div>',
  beforeCreate() {
    if (!this.$store.state[ns]) {
      this.$store.registerModule(ns, HomeModule);
    }
  },
  computed: Vuex.mapState(ns, ['count']),
  methods: Vuex.mapMutations(ns, ['increment']),
});

new Vue({
  el: '#app',
  store: new Vuex.Store(),  // Empty root store
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.1.3/vuex.js"></script>

<div id="app">
  <home></home>
</div>
  • I've used a ns global variable here, but you could obtain it from a prop like in your example.
  • You can dynamically build the module instead of having it hardcoded.
  • You can unregister the module as well upon component destruction if necessary.
like image 29
Decade Moon Avatar answered Oct 23 '25 02:10

Decade Moon