web-dev-qa-db-fra.com

Quelle est la bonne façon de transmettre les accessoires en tant que données initiales dans Vue.js 2?

Je souhaite donc transmettre des accessoires à un composant Vue, mais je m'attends à ce que ces accessoires changent à l'avenir de l'intérieur de ce composant, par exemple. quand je mets à jour ce composant Vue de l'intérieur en utilisant AJAX. Donc, ils ne sont que pour l'initialisation du composant.

Mon cars-list Vue élément du composant où je passe des propriétés avec les propriétés initiales à single-car:

// cars-list.vue

<script>
    export default {
        data: function() {
            return {
                cars: [
                    {
                        color: 'red',
                        maxSpeed: 200,
                    },
                    {
                        color: 'blue',
                        maxSpeed: 195,
                    },
                ]
            }
        },
    }
</script>

<template>
    <div>
        <template v-for="car in cars">
            <single-car :initial-properties="car"></single-car>
        </template>
    </div>
</template>

La façon dont je le fais maintenant c’est que, dans mon composant single-car, j’assigne this.initialProperties à mon this.data.properties sur le hook d’initialisation created(). Et cela fonctionne et est réactif.

// single-car.vue

<script>
    export default {
        data: function() {
            return {
                properties: {},
            }
        },
        created: function(){
            this.data.properties = this.initialProperties;
        },
    }
</script>

<template>
    <div>Car is in {{properties.color}} and has a max speed of {{properties.maxSpeed}}</div>
</template>

Mais mon problème avec cela est que je ne sais pas si c'est une bonne façon de le faire? Cela ne va-t-il pas me causer des ennuis sur la route? Ou y a-t-il une meilleure façon de le faire?

63
Dominik Serafin

Merci à cela https://github.com/vuejs/vuejs.org/pull/567 Je connais la réponse maintenant.

Méthode 1

Passez le support initial directement aux données. Comme dans l'exemple de la documentation mise à jour:

props: ['initialCounter'],
data: function () {
    return {
        counter: this.initialCounter
    }
}

Mais gardez à l’esprit que si l’application passée est un objet ou un tableau utilisé dans l’état du composant parent, toute modification apportée à cet accessoire entraînera la modification de cet état.

Attention : cette méthode n'est pas recommandée. Cela rendra vos composants imprévisibles. Si vous devez définir des données parent à partir de composants enfants, utilisez la gestion d’état comme Vuex ou utilisez "v-model". https://vuejs.org/v2/guide/components.html#Using-v-model-on-Components

Méthode 2

Si votre prop initial est un objet ou un tableau et que vous ne souhaitez pas que les modifications dans l'état enfants se propagent dans l'état parent, utilisez simplement, par exemple. Vue.util.extend [1] pour faire une copie des accessoires en le dirigeant directement vers les données des enfants, comme ceci:

props: ['initialCounter'],
data: function () {
    return {
        counter: Vue.util.extend({}, this.initialCounter)
    }
}

Méthode 3

Vous pouvez également utiliser spread pour cloner les accessoires. Plus de détails dans la réponse d'Igor: https://stackoverflow.com/a/51911118/3143704

Mais gardez à l'esprit que les opérateurs de diffusion ne sont pas pris en charge par les navigateurs plus anciens et que, pour une meilleure compatibilité, vous devez transpiler le code, par exemple. en utilisant babel.

Notes de bas de page

[1] N'oubliez pas qu'il s'agit d'un utilitaire interne Vue et qu'il peut changer avec les nouvelles versions. Vous pouvez utiliser d'autres méthodes pour copier cet accessoire, voir " Comment cloner correctement un objet JavaScript? ".

Mon violon où je le testais: https://jsfiddle.net/sm4kx7p9/3/

66
Dominik Serafin

Je crois que vous le faites bien parce que c'est ce qui est écrit dans la documentation.

Définir une propriété de données locale qui utilise la valeur initiale de l'accessoire comme valeur initiale

https://vuejs.org/guide/components.html#One-Way-Data-Flow

11
jonan.pineda

En réponse à la réponse de @ dominik-serafin:

Si vous passez un objet, vous pouvez facilement le cloner à l'aide de l'opérateur spread (syntaxe ES6):

 props: {
   record: {
     type: Object,
     required: true
   }
 },

data () { // opt. 1
  return {
    recordLocal: {...this.record}
  }
},

computed: { // opt. 2
  recordLocal () {
    return {...this.record}
  }
},

Mais le plus important est de ne pas oublier d'utiliser opt. 2 si vous transmettez une valeur calculée ou une valeur asynchrone supérieure à celle-ci. Sinon, la valeur locale ne sera pas mise à jour.

Démo:

Vue.component('card', { 
  template: '#app2',
  props: {
    test1: null,
    test2: null
  },
  data () { // opt. 1
    return {
      test1AsData: {...this.test1}
    }
  },
  computed: { // opt. 2
    test2AsComputed () {
      return {...this.test2}
    }
  }
})

new Vue({
  el: "#app1",
  data () {
    return {
      test1: {1: 'will not update'},
      test2: {2: 'will update after 1 second'}
    }
  },
  mounted () {
    setTimeout(() => {
      this.test1 = {1: 'updated!'}
      this.test2 = {2: 'updated!'}
    }, 1000)
  }
})
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>

<div id="app1">
  <card :test1="test1" :test2="test2"></card>
</div>

<template id="app2">
  <div>
    test1 as data: {{test1AsData}}
    <hr />
    test2 as computed: {{test2AsComputed}}
  </div>
</template>

https://jsfiddle.net/nomikos3/eywraw8t/281070/

10
Igor Parra