Reputation: 7910
I'm quite new with Vue and Vuex so please bear with me.
I want to make the computed function versions()
get called when I change state.template
, but I'm failing to do so. More specifically, when state.template.versions
changes.
This is part of the component that I want to re-render when state.template.versions
changes. You can also see the computed property versions()
which I want to be called:
<el-dropdown-menu class="el-dropdown-menu--wide"
slot="dropdown">
<div v-for="version in versions"
:key="version.id">
...
</div>
</el-dropdown-menu>
...
computed: {
...mapState('documents', ['template', 'activeVersion']),
...mapGetters('documents', ['documentVersions', 'documentVersionById', 'documentFirstVersion']),
versions () {
return this.documentVersions.map(function (version) {
const v = {
id: version.id,
name: 'Draft Version',
effectiveDate: '',
status: 'Draft version',
}
return v
})
},
This is the getter
:
documentVersions (state) {
return state.template ? state.template.versions : []
},
This is the action
:
createProductionVersion (context, data) {
return new Promise((resolve, reject) => {
documentsService.createProductionVersion(data).then(result => {
context.state.template.versions.push(data) // <-- Here I'm changing state.template. I would expect versions() to be called
context.commit('template', context.state.template)
resolve(result)
})
This is the mutation
:
template (state, template) {
state.template = template
},
I've read that there are some cases in which Vue doesn't detect chanegs made to an array, but .push()
seems to be detected. Source: https://v2.vuejs.org/v2/guide/list.html#Caveats
Any idea on why the computed property is not being called when I update context.state.template.versions
?
Upvotes: 2
Views: 1855
Reputation: 7136
The issue may come from state.template = template
. You guessed correctly that it was a reactivity issue, but not from the Array reactivity, but the template
object.
Vue cannot detect property addition or deletion. This includes affecting a complex object to a property. For that, you need to use Vue.set
.
So your mutation should be :
template (state, template) {
Vue.set(state, "template", template)
},
https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
Upvotes: 3
Reputation: 223
Your function won't get called because this is wrong:
context.state.template.versions.push(data)
context.commit('template', context.state.template)
the context.state
object just points to your current state nothing more.
My suggested solution will be:
First You need to declare your store state correctly
state: {
template: {
versions: []
}
}
You need to update your getter to look like this with no unnecessary conditioning:
documentVersions: state => return state.template.versions,
add a new mutation
ADD_VERSION: (state, version) => {
state.template = {
...state.template,
versions: [...state.template.versions, version]
};
}
your action should like this now:
createProductionVersion({commit}, data) {
return new Promise((resolve, reject) => {
documentsService.createProductionVersion(data).then(result => {
commit('ADD_VERSION', data);
resolve(result);
});
});
}
In your component I suggest to change your computed property from a function
to an object that contains a get
and set
methods (set
is optional)
versions: {
get() {
return this.documentVersions.map(function (version) {
const v = {
id: version.id,
name: 'Draft Version',
effectiveDate: '',
status: 'Draft version',
}
return v
})
}
},
Upvotes: 1
Reputation: 3085
I think this error occurred because you did not declare your store state correctly. Make sure you have the versions
property in your template
object.
state: {
template: {
versions: []
}
}
This way, any changes in the versions
property will be detected by vue.
Upvotes: 1