vuex - 是否有可能直接改变状态,即使不推荐?

Yeh*_*sef 8 vue.js vuex

https://vuex.vuejs.org/en/getting-started.html上的文档 说,

你不能直接改变商店的状态.改变商店状态的唯一方法是明确提交突变.

我的问题是,这是一个好的做法,还是Vuex国家内部的工作方式?换句话说,Vuex状态是否以与Vue数据相同的方式反应(它将js对象转换为可观察的对象),还是其他东西?

一个类似的问题 - 您是否可以直接更改操作中的状态而不是创建突变?我知道这是不好的做法,它失去了遵循惯例的一些可追溯性 - 但它有效吗?

acd*_*ior 14

你可以直接改变动作中的状态而不是创建变异吗?我知道这是不好的做法,它失去了遵循惯例的一些可追溯性 - 但它有效吗?

工作,但会发出警告和错误.

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)
Run Code Online (Sandbox Code Playgroud)

谁知道在此之后还有什么可能被打破.

亲眼看看(注意模板中的数据更新):

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
    }
  },
})
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

Vuex状态以与Vue数据相同的方式反应(它将js对象转换为可观察的对象),还是其他东西?

是.实际上,这是Vue本身使商店对象反应.来自Mutations官方文档:

突变遵循Vue的反应性规则

由于Vuex存储的状态由Vue激活,当我们改变状态时,观察状态的Vue组件将自动更新.这也意味着当使用普通Vue时,Vuex突变会受到相同的反应性警告:

  1. 首先要预先初始化商店的所有需要​​字段的初始状态.

  2. 向Object添加新属性时,您应该:

因此,即使在突变代码中,如果您覆盖observable或直接创建新属性(通过不调用Vue.set(obj, 'newProp', newValue)),该对象也不会被动反应.


跟进评论中的问题(好的!)

因此,可观察对象似乎与常规Vue数据略有不同 - 只允许从变异处理程序进行更改.是对的吗?

他们可能,但我不相信他们.文档和证据(见下面的vm.$watch讨论)指出它们与data对象完全相同,至少在反应/可观察行为方面.

对象"如何知道"它是如何从不同的上下文中变异的?

这是一个很好的问题.请允许我改写一下:

如果Vue.set(object, 'prop', data);从Vue内部调用会引发异常(参见上面的演示),为什么Vue.set(object, 'prop', data);在变异函数内调用不会?

答案就在于内部Store.commit()的代码.它通过_withCommit()内部函数执行变异代码.

所有_withCommit()确实是它设置一个标志this._committing,以true(并返回执行突变代码 _committingfalse的exection后).

然后Vuex商店正在观察各州的变量,如果它通知(也就是观察者触发)变量_committing标志发生变化时false发出警告.

(奖励:做注意到vuex使用vm.$watch --see Vue公司的vm.$watchAPI文档,如果你不熟悉它-观察变量,另一种暗示,即国家的目标是相同的数据对象-他们依靠Vue公司的内部.)

现在,为了证明我的观点,让我们通过设置state._committingtrue自己"欺骗"vuex然后Vue.set()从外面调用一个mutator.如下所示,触发任何警告.德勤.

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
    }
  },
})
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)


Ste*_*gin 10

我会让这个变得非常简单:

因为 state 对象已经是reactive,所以可以完全避免使用 getter 和 mutations。Vue 的所有模板、计算的、监视的等将继续像使用组件的数据一样工作。该商店的state行为是shared data object.

但是这样做您将失去实现时间旅行调试、撤消/重做和设置断点的能力,因为您将command design pattern通过使用方法绕过成员的封装。 https://en.m.wikipedia.org/wiki/Command_pattern