vuex: views don't update on vuex state change
I have a store:
//store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import constructor from './modules/constructor'
Vue.use(Vuex);
const debug = process.env.NODE_ENV !== 'production';
export default new Vuex.Store({
modules: {
constructor
},
strict: debug
})
//store/modules/constructor.js
export default {
state: { // initial state
slides: []
},
mutations: {
['constructor.addSlide'](state, type) {
const slides = state.slides;
slides.push({
id: Math.round(Math.random() * 10000),
type,
});
Vue.set(state, 'slides', slides);
},
['constructor.updateSlide'](state, slide) {
const slides = state.slides;
const targetSlide = slides.find(s => s.id === slide.id);
if (targetSlide) targetSlide.data = slide.data;
//Vue.set(state, 'slides', {...slides});
state.slides = Object.assign({}, slides);
}
}
}
I’ve tried different variations guided by http://vuex.vuejs.org/en/mutations.html#mutations-follow-vues-reactivity-rules
On the page I’ve got two almost similar components slides-previews and presentation-editor:
<div class="presentation-construtor">
<slides-previews :slides="$store.state.constructor.slides"></slides-previews>
<presentation-editor :slides="$store.state.constructor.slides"></presentation-editor>
<templates-list @sidebar-toggle="toggleSidebar"></templates-list>
</div>
<presentation-editor>:
<div class="slide-editor">
<div class="viewport">
<div class="wrap">
<div class="slide-holder" v-for="slide in slides">
<div class="slide-container">
<component :is="slide.type" :data="slide.data" :id="slide.id"></component>
</div>
</div>
</div>
</div>
</div>
and currently one slide type:
<template>
<div class="slide presentation-slide">
<div class="label">Идея</div>
<div class="column" v-for="(value, index) in columns">
<text-editor :content="value.title" mode="inline" @change="setTitle(index, ...arguments)"></text-editor>
<text-editor :content="value.body" mode="partial" @change="setBody(index, ...arguments)"></text-editor>
</div>
<div class="controls">
<button v-if="data.columns.length < 2" @click="addColumn">+</button>
</div>
</div>
</template>
<script>
export default{
props: {
id: {},
data: {
default: () => {
return {
columns: [
{
title: 'Заголовок',
body: 'Контент'
}
]
}
}
}
},
components: {
textEditor: require('../ui/text-editor.vue')
},
methods: {
addColumn()
{
let data = this.data;
data.columns.push({
title: 'Заголовок',
body: 'Контент'
});
this.update(data);
},
setTitle(column, value)
{
let data = this.data;
data.columns[column].title = value;
this.update(data);
},
setBody(column, value)
{
let data = this.data;
data.columns[column].body = value;
this.update(data);
},
update(data) {
this.$store.commit('constructor.updateSlide', {
id: this.id,
data
});
}
}
}
</script>
Both store actions update vuex state and this is seen in vuex inspector.
When I commit constructor.addSlide that pushes a new slide in the array — it updates both slides-previews and presentation-editor, however commiting constructor.updateSlide, that changes the data of some slide does not affect all instances:

The same in opposite way: if I change something in previews, state changes but editor is not affected.
Also even after constructor.addSlide previously changed slides don’t update, only new one is added in both components
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 7
- Comments: 19 (5 by maintainers)
@ktsn can you give an example of how you would implement your last comment? I also have a state with an array of objects that I need to update. Running into the same issue and not finding any solution to work well
Thanks to @kirillgroshkov I solved my problem!
In my case, I was changing an object inside an array. Say:
state.arr[id].status = !state.arr[id].statusWhat I had to do was force the array to change so that it triggers a re-render:
state.arr = state.arr.map((e, i) => { if (i === id) { e.status = !e.status } return e })This seems fundamental to Vuex. I am trying to update state from a mutation but not having reactivity for updating the state
Ran into the same issue. Solved by
replacingthe object one level higher than array in the store:I don’t know if it’s relevant. But what I tried is to go with different ways to update store inside mutation, and this way finally worked. Not obvious at all.
Looks like you are mutating store state in
slide-idea. http://gitlab.terion.name/kzmr/plan-n-go/blob/master/resources/assets/js/app/components/slides/slide-idea.vue#L89Object.assignwon’t update nested object reference. So,data.columnsis same reference as store state.code as satan asfffffffffffff
@ktsn ah. indeed. added
deep-copylib, seems to work fine now. Thank you so much.Maybe some tooling for this should be added to core? For vuex-way it seems to be a very common case.
Thanks for providing your repository. Took a quick look, there are a few problem in your code.
The main reason of not updating the view is you do not refer the store data in
slide-idea. There is default data and it is used for rendering. In addition, the store data is not passed toslide-idea.slide-previewpassesslide.dataon this line but the store data does not seem to havedataproperty.