web-dev-qa-db-fra.com

Les propriétés Vuex $ store ne sont pas réactives lors de l'utilisation d'une propriété calculée

J'ai un magasin Vuex, que j'injecte dans mon instance:

import store from '../store';

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

Et je crée une propriété calculée à partir de ce magasin dans le composant:

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

Cela crée le this.isWide propriété du modèle lors de l'initialisation du composant, mais lorsque la valeur de stockage est mise à jour, le composant ne l'enregistre pas - l'ancienne valeur se trouve toujours dans le modèle.

Qu'est-ce que je fais mal ici?

13
babbaggeii

Votre code devrait fonctionner si vous configurez tout correctement: http://codepen.io/CodinCat/pen/RKZeZe?editors=101

Une erreur très courante est que vous n'avez pas donné les données initiales de votre état.

Vous devez déclarer explicitement la forme d'état, donc au lieu de

state: {}

// or

state: {
  nav: {}
}

faites ceci:

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

ou les propriétés ne seront pas réactives, comme cet exemple: http://codepen.io/CodinCat/pen/ggxBEV?editors=101

Et assurez-vous d'avoir mis à jour l'état, peut-être que le problème est simplement que vous n'avez pas mis à jour l'état correctement comme prévu.

15
CodinCat

En fait, vous devez utiliser la fonction Vue.set () pour rendre la nouvelle propriété réactive.

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

Voir ce codepen: https://codepen.io/DedicatedManager/pen/JZgpaa

J'ai fait une vidéo de capture d'écran entière sur ce sujet: youtu.be/8GHczab2Lbs

2
Dedicated Managers

vous ne devez pas manipuler les objets du magasin directement à partir des méthodes des composants, vous devez valider les mutations sur l'objet du magasin. Les mutations sont des fonctions qui ont des écouteurs et lorsqu'elles sont appelées, les variables modifiées sont suivies et les modifications sont propagées. Si vous devez faire quelque chose d'asynchrone comme soumettre des données au serveur, vous devez même aller plus loin pour définir des actions sur le magasin, faire un appel asynchrone, puis valider des mutations à partir de là pour mettre à jour l'objet d'état. Je sais que cela semble si ennuyeux, mais une fois que vous y êtes habitué, c'est assez simple.

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=101

il fonctionne également directement sur stat.nav sans type https://codepen.io/zoransa/pen/xPrLyW?editors=101

1
Zoran

Lorsque vous ajoutez de nouvelles propriétés à un objet à partir de votre magasin Vuex, vous devez soit utiliser

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

ou remplacez cet objet par un nouveau

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

De Documents Vuex

1
ssten

C'était mon problème.

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

J'ai oublié de définir l'état initial et maintenant il est réactif.

0
chovy