文档here

你不能直接改变store 的状态.改变store 状态的唯一方法是committing mutations.

我的问题是,这是一种良好的做法,还是Vuex状态的内部运作方式?换句话说,Vuex状态是否与Vue数据的react 方式相同(它将JS对象转换为可观察对象),还是其他什么?

一个类似的问题——你能直接改变动作中的状态,而不是制造Mutations 吗?我知道这是一种不好的做法,它失go 了遵循惯例所提供的一些可追溯性——但它有效吗?

推荐答案

你能直接改变动作中的状态而不是制造Mutations 吗?我知道这是一种不好的做法,它失go 了遵循惯例所提供的一些可追溯性——但它有效吗?

工作正常,但会抛出警告和错误.

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状态的react 方式与Vue数据的react 方式相同(它将js对象转换为可观察对象),还是其他什么?

对事实上,正是Vue本身使store 对象具有react 性.从Mutations official docs人中:

Mutations 遵循Vue的react 性规则

由于Vue使Vuexstore 的状态变为react 状态,所以当我们改变

  1. 更喜欢用所有需要的字段预先初始化store 的初始状态.

  2. 向对象添加新属性时,应:

    • 使用Vue.set(obj, 'newProp', 123),或

    • 用一个新的替换那个物体.例如,使用stage-3 object spread syntax我们可以

      state.obj = { ...state.obj, newProp: 123 }
      

因此,即使在代码中,如果覆盖可观察对象或直接创建新属性(不调用Vue.set(obj, 'newProp', newValue)),对象也不会是被动的.


跟进 comments 中的问题(好的!)

因此,可观察对象似乎与常规Vue数据略有不同——变化只允许在变异处理程序中发生.是这样吗?

他们可能是,但我不相信他们是.文件和证据(见下文vm.$watch条讨论)指出,它们与data个物体完全相同,至少在react /可观察行为方面是如此.

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

这是个好问题.请允许我重新措辞:

如果从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 truethen执行Mutations 代码(执行后返回_committingfalse).

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的内部 struct .)

现在,为了证明我的观点,让我们自己打"trick" vuex by setting 100 to 101,然后从变异子外面打Vue.set().如下图所示,no warning被触发.touch .

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>

Vue.js相关问答推荐

vite - 具有相对assets资源 路径的子页面

props至少应该定义它们的类型

Vuetify 置顶工具栏

使用 v-slot:body 时 Vuetify v-data-table 没有响应

Vue 和 Bootstrap Vue - 动态使用插槽

如何为 Vue 项目设置 lint-staged?

为什么当我 Select 第二个输入框时音译transliteration不起作用?

为什么 CSS 关键帧动画在具有范围样式的 Vue 组件中被 destruct ?

W3C 验证和 Vue 的 HTML 绑定语法

将 props 传递给 Vue 组件中的元素属性

Vue test-utils 如何测试 router.push()

SVG 加载 vue-svg-loader; [Vue 警告]:无效的组件定义

Vue:如何在按钮单击时调用 .focus()

Vue 3:模块 '"../../node_modules/vue/dist/vue"' 提示

输入文件 Select 事件在 Select 同一文件时未触发

脚本npm run dev和npm run watch是做什么用的?

mount() 仅在组件 Vue.js 上运行一次

表格行上的 Vuejs 转换

使用 CloudFront 部署在 S3 上的 VueJS 应用程序的指定的密钥不存在

vue-cli@3 没有可用于依赖类型的模块工厂:CssDependency