web-dev-qa-db-fra.com

VueJS: bonne façon de modifier un objet sans changer les données parent

Dans mon composant de vue parent, j'ai un objet user.

Si je transmets cet objet utilisateur à un composant enfant en tant que prop:

<child :user="user"></child>

et dans mon composant enfant, je mets à jour user.name, il sera également mis à jour dans le parent. 

Je souhaite modifier l'objet utilisateur dans le composant enfant sans que les modifications soient reflétées dans l'objet utilisateur figurant dans le composant parent.

Y at-il un meilleur moyen d’y parvenir que de cloner l’objet avec: JSON.parse(JSON.stringify(obj))?

8
user3743266

Vous n'êtes pas obligé d'utiliser l'objet JSON.

const child = {
  props:["user"],
  data(){
    return {
      localUser: Object.assign({}, this.user)
    }
  }
}

Utilisez localUser (ou comme vous voulez l'appeler) dans votre enfant.

Modifier

J'avais modifié un violon créé pour une autre réponse à cette question afin de démontrer le concept ci-dessus et @ user3743266 demandé

J'arrive à le résoudre moi-même et je le trouve très utile. Votre exemple fonctionne bien. Dans l'enfant, vous avez créé un élément dans les données qui prend une copie de l'accessoire et l'enfant travaille avec la copie. Intéressant et utile, mais ... ce n'est pas clair pour moi lorsque la copie locale est mise à jour si quelque chose d'autre modifie le parent. J'ai modifié votre violon en enlevant les v-ifs pour que tout soit visible et dupliquer le composant d'édition. Si vous modifiez le nom en un composant, l’autre est orphelin et n’obtient aucun changement?

Le composant actuel ressemble à ceci:

Vue.component('edit-user', {
  template: `
  <div>
    <input type="text" v-model="localUser.name">
    <button @click="$emit('save', localUser)">Save</button>
    <button @click="$emit('cancel')">Cancel</button>
  </div>
  `,
  props: ['user'],
  data() {
    return {
      localUser: Object.assign({}, this.user)
    }
  }
})

Comme j'ai pris la décision d'utiliser une copie locale de l'utilisateur, @ user3743266 est correct, le composant n'est pas mis à jour automatiquement. La propriétéuser est mise à jour, mais localUser ne l'est pas. Dans ce cas, si vous vouliez mettre à jour automatiquement les données locales chaque fois que la propriété était modifiée, vous auriez besoin d'un observateur.

Vue.component('edit-user', {
  template: `
  <div>
    <input type="text" v-model="localUser.name">
    <button @click="$emit('save', localUser)">Save</button>
    <button @click="$emit('cancel')">Cancel</button>
  </div>
  `,
  props: ['user'],
  data() {
    return {
      localUser: Object.assign({}, this.user)
    }
  },
  watch:{
    user(newUser){
        this.localUser = Object.assign({}, newUser)
    }
  }
})

Voici la mise à jour fiddle .

Cela vous permet de contrôler totalement quand/si les données locales sont mises à jour ou émises. Par exemple, vous pouvez vérifier une condition avant de mettre à jour l'état local.

  watch:{
    user(newUser){
      if (condition)
        this.localUser = Object.assign({}, newUser)
    }
  }

Comme je l'ai dit ailleurs, il est parfois utile de tirer parti des propriétés mutables des propriétés des objets, mais il peut aussi arriver que vous souhaitiez davantage de contrôle.

15
Bert

vous pouvez avoir une variable de données juste avec les informations que vous voulez éditer localement et charger la valeur dans la méthode créée

data() {
return { localUserData: {name: '', (...)}
}
(...)
created() {
    this.localUserData.name = this.user.name;
}

De cette façon, vous gardez à l'esprit quelles données vous éditez. En fonction des besoins, vous souhaiterez peut-être qu'un observateur mette à jour le localData au cas où l'hôte de l'utilisateur change.

0
Victor Mikó

Selon cela , les enfants "ne peuvent pas" et "ne devraient pas" modifier les données de leurs parents. Mais ici vous pouvez voir que si un parent transmet certaines données réactives en tant que propriété à un enfant, elles sont transmises par référence et le parent voit les modifications apportées par l'enfant. C'est probablement ce que vous voulez la plupart du temps, non? Vous ne modifiez que les données que le parent a explicitement partagées. Si vous voulez que l'enfant ait une copie indépendante de user, vous pouvez le faire avec JSON.parse (JSON.stringify ()), mais attention, vous allez sérialiser les propriétés injectées avec Vue. Quand le ferais-tu? Rappelez-vous que les accessoires sont réactifs, de sorte que le parent peut envoyer un nouvel utilisateur à tout moment, annulant les modifications locales?

Peut-être avez-vous besoin de nous en dire plus sur la raison pour laquelle vous voulez que l'enfant ait sa propre copie? Qu'est-ce que l'enfant va faire avec sa copie? Si l'utilisateur de l'enfant est dérivé de l'utilisateur parent de manière systématique (en mettant en majuscule tout le texte ou quelque chose), examinez les propriétés calculées.

0
bbsimonbb