Vuex - La propriété calculée «nom» a été attribuée mais elle n'a pas de setter


111

J'ai un composant avec une certaine validation de formulaire. Il s'agit d'un formulaire de paiement en plusieurs étapes. Le code ci-dessous est pour la première étape. Je voudrais valider que l'utilisateur a entré du texte, stocker son nom dans l'état global, puis l'envoyer à l'étape suivante. J'utilise vee-validate et vuex

<template>
<div>
    <div class='field'>
        <label class='label' for='name'>Name</label>
        <div class="control has-icons-right">

            <input name="name" v-model="name" v-validate="'required|alpha'" :class="{'input': true, 'is-danger': errors.has('name') }" type="text" placeholder="First and Last">
            <span class="icon is-small is-right" v-if="errors.has('name')">
                <i class="fa fa-warning"></i>
            </span>
        </div>
        <p class="help is-danger" v-show="errors.has('name')">{{ errors.first('name') }}</p>

    </div>
    <div class="field pull-right">
        <button class="button is-medium is-primary" type="submit" @click.prevent="nextStep">Next Step</button>
    </div>
</div>
</template>

<script>
export default {
    methods: {
        nextStep(){
            var self = this;

            // from baianat/vee-validate
            this.$validator.validateAll().then((result) => {
                if (result) {
                    this.$store.dispatch('addContactInfoForOrder', self);
                    this.$store.dispatch('goToNextStep');
                    return;
                }
            });
        }
    },
    computed: {
        name: function(){
            return this.$store.state.name;
        }
    }
}
</script>

J'ai un magasin pour gérer l'état de la commande et enregistrer le nom. En fin de compte, je voudrais envoyer toutes les informations du formulaire en plusieurs étapes au serveur.

export default {
  state: {
    name: '',
  },

  mutations: {
    UPDATE_ORDER_CONTACT(state, payload){
      state.name = payload.name;

    }
  },

  actions: {
    addContactInfoForOrder({commit}, payload) {
      commit('UPDATE_ORDER_CONTACT', payload);
    }
  }
}

Lorsque j'exécute ce code, j'obtiens une erreur qui Computed property "name" was assigned to but it has no setter.

Comment lier la valeur du champ de nom à l'état global? Je voudrais que cela soit persistant afin que même si un utilisateur revient en arrière (après avoir cliqué sur "Étape suivante"), il verra le nom qu'il a entré à cette étape


1
En plus de la réponse de Roy J, il semble que l'utilisation v-ford'un calcul sans passeur jette également cet avertissement.
jsiegal

Réponses:


193

Si vous allez à v-modelun calcul, il a besoin d'un setter . Tout ce que vous voulez qu'il fasse avec la valeur mise à jour (probablement l'écrire dans le $store, étant donné que c'est de quoi votre getter le tire), vous le faites dans le setter.

Si la réécriture dans le magasin se produit via l'envoi de formulaire, vous ne voulez pas v-model, vous voulez simplement définir:value .

Si vous voulez avoir un état intermédiaire, où il est enregistré quelque part mais n'écrase pas la source dans le $storeformulaire jusqu'à la soumission du formulaire, vous devrez créer un tel élément de données.


39
:valuefini v-model. Je vous remercie!
Connor Leech

4
Merci ... réparé ma [vue avertir] aussi. J'avais un tiroir de navigation qui nécessitait (en lecture seule) une valeur true / false, mais j'avais mis un v-model.
GA

29

Ça devrait être comme ça.

Dans votre composant

computed: {
        ...mapGetters({
                nameFromStore: 'name'
            }),
        name: {
           get(){
             return this.nameFromStore
           },
           set(newName){
             return newName
           } 
        }
    }

Dans votre magasin

export const store = new Vuex.Store({
         state:{
             name : "Stackoverflow"
         },
         getters: {
                 name: (state) => {
                     return state.name;
                 }
         }
}

1
Désolé d'avoir ravivé une ancienne réponse, mais pourquoi utiliser un getter dans ce cas? Pourquoi ne pas renvoyer this.nameFromStore depuis mapState? Cela fonctionne aussi bien apparemment.
Jake

@Jake Pour cet exemple donné, ce que vous dites est juste. Mais lorsque vous souhaitez manipuler les données enregistrées dans le magasin, vous pouvez le faire dans getter, mais si vous utilisez this.nameFromStoredirectement, vous ne pouvez pas manipuler les données.
OhhhThatVarun

1
Merci pour la clarification :)
Jake

@Jake Pas de problème!
OhhhThatVarun

4

Pour moi, cela changeait.

this.name = response.data;

À ce que le calcul renvoie ainsi;

this.$store.state.name = response.data;

-1

Je veux juste mentionner pourquoi cet avertissement apparaît, chaque fois que nous créons une valeur calculée, il est getter par défaut, nous devons explicitement définir des setters pour la propriété calculée,

comme mentionné dans la documentation de VueJs, Computed Setter

votre propriété calculée ressemblera à ceci

   name: {
       get: function () {
          return yourName
       },
       set: function (newName) {
          return yourNewName
       }

Une manière plus appropriée est que vous utilisez mapStatepour obtenir le nom du magasin, et une autre option que vous définissez getter dans votre magasin et que vous utilisez mapGetterspour extraire le nom du magasin,

Chose importante à savoir: les getters en magasin sont utilisés lorsque vous souhaitez obtenir des données calculées à partir du magasin, puis à ce moment-là, vous définissez la logique dans les getters qui vous permettent d'obtenir des données calculées

exemple de getter

getters = {
  isLoggedIn (state) {
    return !!state?.activeUser?.id
  }
}

ce getter vérifie votre état pour l'utilisateur actif et retourne vrai si connecté et faux si non connecté,

plus tard dans toute l'application, nous utilisons mapGetterspour extraire ceisLoggedIn propriété et ajouter des vérifications en fonction de cela

j'espère que quelqu'un trouvera cette aide complète :)

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.