我还在学习Vue,但我无法理解为什么会出现这种错误。
错误:[vuex]不要在突变处理程序之外改变vuex存储状态。
这是我的代码:
const DATE_FORMAT = "DD-MM-YYYY";
Vue.filter("formatDate", function(value, dateFormat) {
dateFormat = dateFormat ? dateFormat : DATE_FORMAT;
if (value) {
return moment(String(value)).format(dateFormat);
}
});
Vue.component('list-component', {
props: ['projects'],
template:
`
<div>
<ul v-for="project in projects" :key="project.id">
<li v-for="(value, key) in project" :key="key">
{{ key }}: {{ value }}
</li>
<hr />
</ul>
</div>
`
});
const store = new Vuex.Store({
state: {
projects: [{
id: 1,
name: "super project",
startDate: "2014-09-01T08:18:28+02:00"
}, {
id: 2,
name: "extra project",
startDate: "2017-12-20T07:28:23.133+01:00"
}, {
id: 3,
name: "small project",
startDate: "2017-12-20T07:28:23.133+01:00"
}]
},
getters: {
allProjects: state => state.projects
},
strict: true
});
new Vue({
el: '#app',
computed: {
formattedProjects() {
var project = store.getters.allProjects;
project.forEach(project => {
project.startDate = this.$options.filters.formatDate(project.startDate);
});
return project;
}
}
});
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.js"></script>
<script src="https://unpkg.com/vuex@3.0.1/dist/vuex.js"></script>
<script src="https://unpkg.com/vue@2.5.13/dist/vue.js"></script>
<div id="app">
<list-component :projects="formattedProjects"></list-component>
</div>
&#13;
https://jsfiddle.net/9sn78n1h/2/
我无法在组件中使用我的过滤器,因为属性名称可能不同。在上面的示例中,它是startDate
,但在其他数据中,它可以是addDate
,endDate
等。
在vuex商店中,我需要格式原样startDate
,我不想改变它。
我不确定在像allProjectsWithFormatedDate
这样的vuex中编写另一个getter是一个很好的做法,但即便如此,它仍然会对变异商店大吼大叫。
所以我在我的计算方法project
中创建了一个局部变量formattedProjects()
,我不知道为什么我在更改它的值后会出现这个错误。< / p>
有人可以帮助我理解它并展示解决这个问题的正确方法吗?
我知道我可以将strict
模式设置为false
以隐藏此错误(我应该在制作中),但我相信有更好的方法可以解决此问题。
答案 0 :(得分:1)
很简单,因为您在不使用dispatch
或mutations
的情况下直接修改状态。
有关详细信息,请参阅this页面。
在上面的示例中,您可以添加以下内容:
mutations: {
updateProject (state, obj) {
// Use state, get the project then set startDate.
// You can use obj.projectId and obj.startDate
}
}
然后在循环中进行更改:
this.$store.commit('updateProject', {
projectId: project.id,
startDate: this.$options.filters.formatDate(project.startDate)
})
如果您添加了Vue实例,它将允许您在没有警告的情况下更新状态。
根据州的规模和应用的复杂程度,您可以考虑改用modules。
与您的评论一致,如果您没有尝试更新商店,只需在新对象中返回数据:
formattedProjects() {
var project = store.getters.allProjects;
var clone = []
project.forEach(project => {
clone.push({
...project,
startData: this.$options.filters.formatDate(project.startDate)
})
});
return clone;
}
这将返回 new 对象,而不会改变商店值。可能有一种更短的方式来返回数据,但在我测试时使用.map
会导致问题但你应该能够理解......
注意:另一个想法是遍历组件上的状态,只是在组件HTML中进行过滤 - 不确定为什么需要使用计算的道具进行过滤。
您已更新示例:
const DATE_FORMAT = "DD-MM-YYYY";
Vue.filter("formatDate", function(value, dateFormat) {
dateFormat = dateFormat ? dateFormat : DATE_FORMAT;
if (value) {
return moment(String(value)).format(dateFormat);
}
});
Vue.component('list-component', {
props: ['projects'],
template:
`
<div>
<ul v-for="project in projects" :key="project.id">
<li v-for="(value, key) in project" :key="key">
{{ key }}: {{ value }}
</li>
<hr />
</ul>
</div>
`
});
const store = new Vuex.Store({
state: {
projects: [{
id: 1,
name: "super project",
startDate: "2014-09-01T08:18:28+02:00"
}, {
id: 2,
name: "extra project",
startDate: "2017-12-20T07:28:23.133+01:00"
}, {
id: 3,
name: "small project",
startDate: "2017-12-20T07:28:23.133+01:00"
}]
},
getters: {
allProjects: state => state.projects
},
strict: true
});
new Vue({
el: '#app',
computed: {
formattedProjects() {
var project = store.getters.allProjects;
var clone = []
project.forEach(project => {
clone.push({
...project,
startData: this.$options.filters.formatDate(project.startDate)
})
});
return clone;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.js"></script>
<script src="https://unpkg.com/vuex@3.0.1/dist/vuex.js"></script>
<script src="https://unpkg.com/vue@2.5.13/dist/vue.js"></script>
<div id="app">
<list-component :projects="formattedProjects"></list-component>
</div>
答案 1 :(得分:1)
问题出在错误信息中。 Vuex具有单向流,您必须注意这一点。对状态的任何更改都只能在突变部分进行。所以我们错误地改变了下面一行的对象。
project.startDate = this.$options.filters.formatDate(project.startDate);
这将在商店项project
上添加/更新(mutate)startDate属性。这是问题的根本原因。我认为Vuex必须有更好的方法来处理这个问题。如果你想在你的计算属性本身处理它,可以这样做。
formattedProjects() {
var clonedProject = []
var project = store.getters.allProjects;
project.forEach(project => {
clonedProject.push({
...project,
startData: this.$options.filters.formatDate(project.startDate)
})
});
return clonedProject;
}
以下是fiddle
的链接