web-dev-qa-db-fra.com

VueJs 2.0 - comment écouter les modifications de `props`

Dans les VueJs 2.0 docs , je ne trouve aucun crochet qui puisse écouter lorsque props change.

Est-ce que VueJs a de tels crochets comme onPropsUpdated() ou similaire?

Mettre à jour

Comme @wostex l'a suggéré, j'ai essayé de watch ma propriété mais rien n'a changé. Puis j'ai réalisé que j'avais un cas particulier:

<template>
    <child :my-prop="myProp"></child>
</template>

<script>
   export default {
      props: ['myProp']
   }
</script>

Je passe myProp que le composant parent reçoit au composant child. Alors le watch: {myProp: ...} ne fonctionne pas.

165
Amio.io

Vous pouvez watch props pour exécuter du code lors de leurs modifications:

new Vue({
  el: '#app',
  data: {
    text: 'Hello'
  },
  components: {
    'child' : {
      template: `<p>{{ myprop }}</p>`,
      props: ['myprop'],
      watch: { 
        myprop: function(newVal, oldVal) { // watch it
          console.log('Prop changed: ', newVal, ' | was: ', oldVal)
        }
      }
    }
  }
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="app">
  <child :myprop="text"></child>
  <button @click="text = 'Another text'">Change text</button>
</div>
206
Egor Stambakio

Avez-vous essayé cela?

watch: {
  myProp: {
    // the callback will be called immediately after the start of the observation
    immediate: true, 
    handler (val, oldVal) {
      // do your stuff
    }
  }
}

https://vuejs.org/v2/api/#watch

48
BearInBox

Il,

dans mon cas, j'avais besoin d'une solution où, à tout moment, les accessoires changeraient, je devais analyser à nouveau mes données. J'étais fatigué de faire de l'observateur séparé pour tous mes accessoires, alors j'ai utilisé ceci:

  watch: {
    $props: {
      handler() {
        this.parseData();
      },
      deep: true,
      immediate: true,
    },

Le point clé à retenir de cet exemple est d'utiliser deep: true afin qu'il ne surveille pas seulement $ props, mais également ses valeurs imbriquées telles que p. Ex. props.myProp

Vous pouvez en savoir plus sur ces options de surveillance étendues ici: https://vuejs.org/v2/api/#vm-watch

10
JoeSchr

Vous devez comprendre la hiérarchie des composants que vous rencontrez et la manière dont vous transmettez les accessoires. Il est certain que votre cas est spécial et que les développeurs ne le rencontrent généralement pas.

Composant parent -myProp-> Composant enfant -myProp-> Composant petits-enfants

Si myProp est modifié dans le composant parent, il sera reflété dans le composant enfant également.

Et si myProp est modifié dans le composant enfant, il sera reflété dans le composant petitchild également.

Donc, si myProp est modifié dans le composant parent, alors il sera reflété dans le composant petitchild. (jusqu'ici tout va bien).

Par conséquent, dans la hiérarchie, vous n'avez rien à faire, les accessoires seront intrinsèquement réactifs.

Parlons maintenant de la hiérarchie

Si myProp est modifié dans le composant grandChild, il ne sera pas reflété dans le composant enfant. Vous devez utiliser le modificateur .sync dans enfant et émettre un événement à partir du composant grandChild.

Si myProp est modifié dans le composant enfant, il ne sera pas reflété dans le composant parent. Vous devez utiliser le modificateur .sync dans parent et émettre un événement à partir du composant enfant.

Si myProp est modifié dans le composant grandChild, il ne sera pas reflété dans le composant parent (évidemment). Vous devez utiliser le modificateur .sync enfant et émettre un événement du composant grandchild, puis regarder le composant prop dans le composant enfant et émettre un événement lors de la modification qui est écoutée par le composant parent à l'aide du modificateur .sync.

Voyons du code pour éviter toute confusion

Parent.vue

<template>
    <div>
    <child :myProp.sync="myProp"></child>
    <input v-model="myProp"/>
    <p>{{myProp}}</p>
</div>
</template>

<script>

    import child from './Child.vue'

    export default{
        data(){
            return{
                myProp:"hello"
            }
        },
        components:{
            child
        }
    }
</script>

<style scoped>
</style>

Child.vue

<template>
<div>   <grand-child :myProp.sync="myProp"></grand-child>
    <p>{{myProp}}</p>
</div>

</template>

<script>
    import grandChild from './Grandchild.vue'

    export default{
        components:{
            grandChild
        },
        props:['myProp'],
        watch:{
            'myProp'(){
                this.$emit('update:myProp',this.myProp)

            }
        }
    }
</script>

<style>

</style>

Petit-enfant.vue

<template>
    <div><p>{{myProp}}</p>
    <input v-model="myProp" @input="changed"/>
    </div>
</template>

<script>
    export default{
        props:['myProp'],
        methods:{
            changed(event){
                this.$emit('update:myProp',this.myProp)
            }
        }
    }
</script>

<style>

</style>

Mais après cela, vous ne ferez pas attention aux avertissements criants de vue disant

'Évitez de muter directement un accessoire, car la valeur sera écrasée à chaque nouvelle restitution du composant parent.'

Encore une fois, comme je l’ai mentionné précédemment, la plupart des développeurs ne rencontrent pas ce problème, car c’est un modèle anti-modèle. C'est pourquoi vous obtenez cet avertissement.

Mais afin de résoudre votre problème (selon votre conception). Je crois que vous devez faire le travail ci-dessus autour (bidouille pour être honnête). Je vous recommande néanmoins de repenser votre conception et de réduire les risques de bugs.

J'espère que ça aide.

7
Ankit Kumar Ojha

Je ne sais pas si vous l'avez résolu (et si je comprends bien), mais voici mon idée:

Si le parent reçoit myProp et que vous souhaitez le transmettre à l'enfant et le regarder dans l'enfant, il doit alors disposer d'une copie de myProp (non de référence).

Essaye ça:

new Vue({
  el: '#app',
  data: {
    text: 'Hello'
  },
  components: {
    'parent': {
      props: ['myProp'],
      computed: {
        myInnerProp() { return myProp.clone(); } //eg. myProp.slice() for array
      }
    },
    'child': {
      props: ['myProp'],
      watch: {
        myProp(val, oldval) { now val will differ from oldval }
      }
    }
  }
}

et en html:

<child :my-prop="myInnerProp"></child>

en fait, vous devez être très prudent lorsque vous travaillez sur des collections complexes dans de telles situations (transmission à plusieurs reprises).

6
m.cichacz

pour une liaison bidirectionnelle, vous devez utiliser le modificateur .sync

<child :myprop.sync="text"></child>

plus de détails ...

et vous devez utiliser la propriété watch dans le composant enfant pour écouter et mettre à jour les modifications.

props: ['myprop'],
  watch: { 
    myprop: function(newVal, oldVal) { // watch it
      console.log('Prop changed: ', newVal, ' | was: ', oldVal)
    }
  }
3
Md Mahamudul Hasan

Je travaille avec une propriété calculée comme:

    items:{
        get(){
            return this.resources;
        },
        set(v){
            this.$emit("update:resources", v)
        }
    },

Ressources est dans ce cas une propriété:

props: [ 'resources' ]
2
Wouter Schoofs

Vous pouvez utiliser le mode veille pour détecter les modifications:

Tout faire au niveau atomique. Donc, vérifiez d’abord si la méthode de surveillance elle-même est appelée ou non en consolant quelque chose à l’intérieur. Une fois que la surveillance a été établie, écrasez-la avec votre logique métier.

watch: { 
  myProp: function() {
   console.log('Prop changed')
  }
}
0
Rahul Sharma