【问题标题】:$store properties are not reactive when using computed property (Vuex)使用计算属性 (Vuex) 时,$store 属性不是响应式的
【发布时间】:2017-06-10 15:22:14
【问题描述】:

我有一个 Vuex 商店,我将其注入到我的实例中:

import store from '../store';
    
const mainNav = new Vue({
  el: '#main-nav',
  store,
  components: { NavComponent }
});

我正在组件中从该商店创建一个计算属性:

computed: {
  isWide() {
    return this.$store.state.nav.type === 'wide';
  }
}

这确实会在组件初始化时为模板创建 this.isWide 属性,但是当更新存储值时,组件不会注册它 - 旧值仍在模板上。

我在这里做错了什么?

【问题讨论】:

    标签: javascript vue.js vue-component vuex computed-properties


    【解决方案1】:

    在我的例子中,我只是忘记在我的突变中传递变量“状态”,因此,它不是反应性的

    const mutations = {
      [mutationTypes.storeTaskStart](state) {
        state.isSubmitting = true;
      },
    };
    

    【讨论】:

      【解决方案2】:

      这是我的问题。

      const store = new Vuex.Store({
        state: {
          isTrackPlaying: false,
        },
        ...
      });
      

      我忘了设置初始状态,现在它是响应式的。

      【讨论】:

        【解决方案3】:

        两者都是反应式

        $vm.$set

        this.$set(some_object, 'key', 'value')
        

        Vue.set

        Vue.set(some_object, 'key', 'value')
        

        【讨论】:

          【解决方案4】:

          这就是我解决问题的方法:

          我有包含其他对象的状态对象。每当发生突变时,我都尝试使用 Vue.set,但它很混乱,仍然无法正常工作。 所以我创建了一个名为 toggleState 的布尔状态变量,并为它提供了一个 getter。每当一个突变改变了一个主要的状态对象,它也会做state.stateToggle =! state.stateToggle。 任何关心的人都可以观察 stateToggle 的变化,并做任何需要的事情。在我的例子中,它是用变异的主要对象重新构建一个树视图。

          【讨论】:

            【解决方案5】:

            Vuex 存储向对象添加新属性时,您应该使用

            Vue.set(obj, 'newProp', 123)
            

            或用新的对象替换该对象

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

            来自Vuex docs

            【讨论】:

            • 如果你有多层数组你会怎么做?喜欢something[0].inside[0].value?
            • 我认为最好的方法是制作多级数组的 tmp 副本,然后进行更改。然后覆盖整个something
            【解决方案6】:

            实际上,您需要使用 Vue.set() 函数来使新属性具有反应性。

            changeType () {
               Vue.set(this.$store.state.nav, 'type', 'wide');
            }
            

            查看此代码笔:https://codepen.io/DedicatedManager/pen/JZgpaa

            我为此主题制作了一个完整的屏幕截图视频:youtu.be/8GHczab2Lbs

            【讨论】:

            • 我确定这不是我的问题。绝望,我打开了你的视频。 4:11 进入它,我暂停了它,因为我意识到由于最近的本地更改,对象中的属性实际上并不存在。谢谢你强迫我意识到。
            • 很高兴我的评论有帮助。
            • 这对 Vue 3 有何改变?我得到 Vue 是未定义的。
            • 您能告诉我如何在 Vu3 中更改它吗? Vue.set 似乎不起作用。
            • 我尝试使用 Vue.set 但它仍然没有更新:(
            【解决方案7】:

            你不应该直接从组件方法操作存储对象,你应该在存储对象上提交突变。突变是具有侦听器的函数,并且在调用时会跟踪更改的变量并传播更改。如果你需要做一些异步的事情,比如向服务器提交数据,你甚至需要进一步定义存储上的操作,进行异步调用,然后从那里提交突变以更新状态对象。我知道这听起来很烦人,但是一旦你习惯了它就很简单了。

            const store = new Vuex.Store({
              state: {
                nav: {
                  type: 'not wide by default'
                }
              },
              mutations: {
                changeType: (state, type) => {
                  state.nav.type = type;
                }
              }
            })
            
            Vue.component('NavComponent', {
              template: '<div>isWide?: {{isWide}}</div>',
              computed: {
                isWide () {
                  return this.$store.state.nav.type === 'wide'
                }
              }
            })
            
            new Vue({
              el: '#app',
              store,
              methods: {
                changeType (type) {
                  this.$store.commit('changeType', type);
                }
              }
            })
            <script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/2.1.0/vuex.js"></script>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.js"></script>
            <div id="app">
              <nav-component></nav-component>
              <button @click="changeType('wide')">
                Change to Wide
              </button>
              <button @click="changeType('narrow')">
                Change to Narrow
              </button>
            </div>

            https://codepen.io/zoransa/pen/KyqvWd?editors=1010

            它也可以直接在 stat.nav 中使用,无需类型 https://codepen.io/zoransa/pen/xPrLyW?editors=1010

            【讨论】:

            • 这里可以在codepen上运行我显然没有设置好
            • Tbh 我没有在我的 vue 应用程序中使用存储突变,因为我通常有太多东西要从应用程序中的太多地方以太多不同的方式进行更改,这将是一个痛苦的背后必须为每种情况编写一个函数。
            • 嗨尼克,你不必把所有东西都放在商店里,只有你在多个地方使用的数据,让组件有自己的数据和访问权限来存储槽计算属性和你需要发送的更新无论如何,它们都经历了突变
            • 似乎我也可以从组件内部更改存储中的数据(没有突变)
            • 是的,有些人实际上不使用完整的 vuex,而是做一些类似的事情......窗口级别上最简单的数据对象 let state = { user: 'John', age: 38};然后在 vue data 中放入 data() { state: state, something: 'whatever'}
            【解决方案8】:

            如果您正确设置所有内容,您的代码应该可以工作:http://codepen.io/CodinCat/pen/RKZeZe?editors=1010

            一个非常常见的错误是您没有提供您的州初始数据。

            您应该明确声明状态形状,而不是

            state: {}
            
            // or
            
            state: {
              nav: {}
            }
            

            这样做:

            state: {
              nav: {
                type: '...'
              },
              ...
            }
            

            否则属性将不会反应,例如:http://codepen.io/CodinCat/pen/ggxBEV?editors=1010

            并确保您确实更新了状态,也许问题只是您没有按预期正确更新状态。

            【讨论】:

            • 太棒了——这是正确的答案。我认为所有对象都是这种情况,而不仅仅是 Vuex?
            • 组件数据相同。如果不给出初始状态,Vue 无法将其转换为响应式
            • “并确保您确实更新了状态,也许问题只是您没有按预期正确更新状态。” - 这是票
            • “一个很常见的错误是你没有给你的状态初始数据” -> 这个。
            猜你喜欢
            • 2018-10-12
            • 1970-01-01
            • 2020-12-29
            • 1970-01-01
            • 2019-10-19
            • 2020-05-07
            • 1970-01-01
            • 1970-01-01
            • 2020-08-11
            相关资源
            最近更新 更多