说,
You cannot directly mutate the store’s state. The only way to change a store’s state is by explicitly committing mutations.
我的问题是,这是一个好的做法,还是Vuex国家内部的工作方式?换句话说,Vuex状态是否以与Vue数据相同的方式反应(它将js对象转换为可观察的对象),还是其他东西?
一个类似的问题 – 您是否可以直接更改操作中的状态而不是创建突变?我知道这是不好的做法,它失去了遵循惯例的一些可追溯性 – 但它有效吗?
解决方法
Could you directly change the state in an action instead of creating a mutation? I know it’s bad practice and it loses some of the traceability that following the conventions gives – but does it work?
工作,但会发出警告和错误.
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,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>
the Vuex state reactive in the same way Vue data is (it converts the js object to an observable),or is it something else?
是.实际上,这是Vue本身使商店对象反应.从Mutations official docs:
Mutations Follow Vue’s Reactivity Rules
Since a Vuex store’s state is made reactive by Vue,when we mutate the
state,Vue components observing the state will update automatically.
This also means Vuex mutations are subject to the same reactivity
caveats when working with plain Vue:
Prefer initializing your store’s initial state with all desired fields upfront.
When adding new properties to an Object,you should either:
Use
Vue.set(obj,'newProp',123)
,orReplace that Object with a fresh one. For example,using the stage-3 07001 we can
write it like this:06003
因此,即使在突变代码中,如果覆盖observable或直接创建新属性(通过不调用Vue.set(obj,’newProp’,newValue)),该对象也不会被动反应.
跟进评论中的问题(好的!)
So it seems the observable object is slightly different than the regular Vue data – changes are only allowed to happen from a mutation handler. Is that right?
他们可能,但我不相信他们.文档和证据(见下面的vm.$watch讨论)指出它们与数据对象完全相同,至少在反应/可观察行为方面.
How does the object “know” it was mutated from a different context?
这是一个很好的问题.请允许我改写一下:
If calling
Vue.set(object,'prop',data);
from within Vue throws an exception (see demo above),why callingVue.set(object,data);
from within a mutation function doesn’t?
答案是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.
(额外奖励: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,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,response.data); // no warning! yay! }).catch(function (error) { console.dir(error); }); },})
<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>