https://vuex.vuejs.org/en/getting-started.html处的文档 说,
您不能直接改变商店的状态。改变商店状态的唯一方法是明确提交突变。
我的问题是,这是一种好的做法,还是Vuex国家的内部工作方式如何?换句话说,Vuex状态是否以与Vue数据相同的方式反应(它将js对象转换为可观察的对象),还是其他东西?
类似的问题 - 您是否可以直接更改操作中的状态而不是创建突变?我知道这是不好的做法,它会失去遵循惯例的一些可追溯性 - 但是它有效吗?
答案 0 :(得分:10)
您可以直接更改操作中的状态而不是创建突变吗?我知道这是不好的做法,它会失去遵循惯例的一些可追溯性 - 但是它有效吗?
工作,但会发出警告并发出错误。
vue.js:584 [Vue warn]: Error in callback for watcher "function () { return this._data.$$state }": "Error: [vuex] Do not mutate vuex store state outside mutation handlers."
(found in <Component>)
warn @ vue.js:584
...
vue.js:1719 Error: [vuex] Do not mutate vuex store state outside mutation handlers.
at assert (VM260 vuex.js:103)
谁知道在此之后还有什么可能被打破。
自己查看(注意模板中的数据更新):
const store = new Vuex.Store({
strict: true,
state: {
people: []
},
mutations: {
populate: function (state, data) {
//Vue.set(state, 'people', data);
}
}
});
new Vue({
store,
el: '#app',
mounted: function() {
let self = this;
this.$http.get('https://api.myjson.com/bins/g07qh').then(function (response) {
// setting without commit
Vue.set(self.$store.state, 'people', response.data);
//self.$store.commit('populate', response.data)
}).catch(function (error) {
console.dir(error);
});
},
computed: {
datadata: function() {
return this.$store.state.people
}
},
})
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuex"></script>
<script src="https://unpkg.com/vue-resource"></script>
<div id="app">
Data: {{ datadata }}
</div>
Vuex状态以与Vue数据相同的方式反应(它将js对象转换为可观察的对象),还是其他东西?
是。实际上,这是Vue本身使商店对象反应。来自Mutations official docs:
突变遵循Vue的反应性规则
由于Vuex商店的状态被Vue反应,当我们改变时 状态,观察状态的Vue组件将自动更新。 这也意味着Vuex突变具有相同的反应性 使用普通Vue时需要注意:
首选初始化商店的初始状态,包括所有需要的字段。
- 醇>
向Object添加新属性时,您应该:
使用
Vue.set(obj, 'newProp', 123)
或用新的Object替换该Object。例如,我们可以使用阶段3 object spread syntax 这样写:
state.obj = { ...state.obj, newProp: 123 }
因此,即使在突变代码中,如果您覆盖observable或直接创建新属性(通过不调用Vue.set(obj, 'newProp', newValue)
),该对象也不会被动反应。
因此,可观察对象似乎与常规Vue数据略有不同 - 只允许从变异处理程序进行更改。是吗?
他们可能,但我不相信他们。文档和证据(见下文vm.$watch
讨论)指出它们与data
对象完全相同,至少在反应/可观察行为方面。
对象如何“知道”它是从不同的上下文中变异的?
这是一个很好的问题。请允许我改写一下:
如果从Vue中调用
Vue.set(object, 'prop', data);
会引发异常(参见上面的演示),为什么在变异函数中调用Vue.set(object, 'prop', data);
呢?
答案在于within Store.commit()
's code。它执行变异代码through a _withCommit()
internal function。
所有this _withCommit()
does is it sets a flag this._committing
to true
和然后执行变异代码(并在执行后将_committing
返回到false
。)
Vuex商店然后是watching the states' variables,如果它通知(也就是观察者触发)variable changed while the _committing
flag was false
it throws the warning。
(Bonus:do notice that vuex uses vm.$watch
- 如果您不熟悉,请查看Vue's vm.$watch
API docs - 观察变量,另一个暗示状态对象与数据对象相同 - 它们依赖于Vue的内部结构。)
现在,为了证明我的观点,让我们自己将state._committing
设置为true
来“欺骗”vuex,然后从mutator外部调用Vue.set()
。如下所示,触发无警告。德勤。
const store = new Vuex.Store({
strict: true,
state: {
people: []
},
mutations: {
populate: function (state, data) {
//Vue.set(state, 'people', data);
}
}
});
new Vue({
store,
el: '#app',
mounted: function() {
let self = this;
this.$http.get('https://api.myjson.com/bins/g07qh').then(function (response) {
// trick the store to think we're using commit()
self.$store._committing = true;
// setting without commit
Vue.set(self.$store.state, 'people', response.data);
// no warning! yay!
}).catch(function (error) {
console.dir(error);
});
},
computed: {
datadata: function() {
return this.$store.state.people
}
},
})
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuex"></script>
<script src="https://unpkg.com/vue-resource"></script>
<div id="app">
Data: {{ datadata }}
</div>
答案 1 :(得分:3)
我将使其变得非常简单:
因为状态对象已经是reactive
,所以您可以完全避免使用获取器和变量。 Vue的所有模板(包括计算,监视等)将继续像使用组件数据一样工作。商店的state
充当shared data object
。
但是,这样做将失去实现时间旅行调试,撤消/重做和设置断点的能力,因为您将通过使用方法来规避command design pattern
和成员的封装。
https://en.m.wikipedia.org/wiki/Command_pattern