Reputation: 615
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?
Upvotes: 4
Views: 3396
Reputation: 34306
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>
ns
global variable here, but you could obtain it from a prop like in your example.Upvotes: 4
Reputation: 35724
The problem with adding values after instantiation is that they don't become reactive without using set
When you are adding a new property that wasn’t present when the data was observed. Due to the limitation of ES5 and to ensure consistent behavior across browsers, Vue.js cannot detect property addition/deletions. The best practice is to always declare properties that need to be reactive upfront. In cases where you absolutely need to add or delete properties at runtime, use the global Vue.set or Vue.delete methods.
try this instead
import Vue from 'vue';
export const selectLimitComponentMutations = function (namespace, prefix){
return {
[`${namespace}/update${prefix}selected_limit`]: (state, newLimit) => {
Vue.$set(state, `${prefix}selected_limit`, newLimit);
}
}
};
Upvotes: 2
Reputation: 22403
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
Upvotes: 8