Jak słuchać zmian "rekwizytów"

W VueJS 2.0 docs nie mogę znaleźć żadnych hooków, które mogłyby słuchać zmian props.

Czy VueJs ma takie haki jak onPropsUpdated() Czy podobne?

Update

Jak zasugerował @wostex, próbowałem watch mojej własności, ale nic się nie zmieniło. Wtedy zdałem sobie sprawę, że mam specjalny przypadek:

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

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

Przekazuję myProp, że komponent macierzysty otrzymuje do komponentu child. Wtedy watch: {myProp: ...} nie działa.

Author: isherwood, 2017-06-16

13 answers

Możesz watch wykonać kod po zmianie właściwości:

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>
 420
Author: Egor Stambakio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-16 08:27:11

Próbowałeś tego ?

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

 114
Author: BearInBox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-04 14:46:24

On,,,,]}

W moim przypadku potrzebowałem rozwiązania, w którym za każdym razem, gdy jakieś rekwizyty się zmienią, musiałem ponownie przeanalizować moje dane. Byłem zmęczony robieniem osobnego watchera dla wszystkich moich rekwizytów, więc użyłem tego: {]}

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

Kluczowym punktem do usunięcia z tego przykładu jest użycie deep: true, aby nie tylko oglądał $props, ale także zagnieżdżał wartości, takie jak np. props.myProp

Możesz dowiedzieć się więcej o tej rozszerzonej opcji zegarka tutaj: https://vuejs.org/v2/api/#vm-watch

 35
Author: JoeSchr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-31 20:29:15

Musisz zrozumieć, jaką hierarchię komponentów posiadasz i jak przekazujesz rekwizyty, zdecydowanie twój przypadek jest wyjątkowy i zwykle nie spotykany przez deweloperów.

Komponent nadrzędny-myProp - > komponent podrzędny-myProp - > wnuk Komponent

Jeśli myProp zostanie zmienione w komponencie nadrzędnym, to będzie również odzwierciedlone w komponencie podrzędnym.

I jeśli myProp zostanie zmieniony w komponencie potomnym, to zostanie odzwierciedlone w wnuku komponent też.

Więc jeśli myProp zostanie zmieniony w komponencie nadrzędnym, to będzie odzwierciedlone w komponencie wnuk. (na razie tak dobrze).

Dlatego w hierarchii nie musisz nic robić rekwizyty będą z natury reaktywne.

Teraz mówi się o awansie w hierarchii

Jeśli myProp zostanie zmieniony w komponencie grandChild, to nie będzie odzwierciedlane w komponencie potomnym. Musisz użyć .modyfikator synchronizacji w zdarzeniu child I emit z wnuka komponent.

Jeśli myProp zostanie zmienione w komponencie potomnym, to nie zostanie odzwierciedlone w komponencie nadrzędnym. Musisz użyć .modyfikator synchronizacji w komponencie nadrzędnym i emituje Zdarzenie z komponentu podrzędnego.

Jeśli myProp zostanie zmienione w komponencie grandChild, to nie zostanie odzwierciedlone w komponencie nadrzędnym (oczywiście). Musisz użyć .Synchronizuj modyfikator potomny i emituj Zdarzenie z komponentu wnuk, a następnie obserwuj właściwość w komponencie potomnym i emituj Zdarzenie przy zmianie, która jest nasłuchiwane przez komponent nadrzędny za pomocą .modyfikator synchronizacji.

Zobaczmy jakiś kod, aby uniknąć zamieszania

Rodzic.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>
Dziecko.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>
Wnuk.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>

Ale po tym nie zauważysz krzyczących ostrzeżeń vue mówiących

' unikaj mutacji właściwości bezpośrednio, ponieważ wartość zostanie nadpisana za każdym razem, gdy komponent macierzysty ponownie renderuje.'

Ponownie, jak wspomniałem wcześniej, większość deweloperów nie napotyka tego problemu, bo to anty wzór. Dlatego dostajesz to Ostrzeżenie.

Ale w celu rozwiązania problemu (zgodnie z Twoim projektem). Uważam, że musisz wykonać powyższą pracę (hack, aby być szczerym). Nadal zalecam, abyś przemyślał swój projekt i zrobił mniej podatny na błędy.

Mam nadzieję, że to pomoże.
 9
Author: Ankit Kumar Ojha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-09 05:07:39

Nie wiem, czy to rozwiązałeś (i jeśli dobrze rozumiem), ale oto mój pomysł:

Jeśli rodzic otrzymuje myProp, a Ty chcesz, aby przeszedł do child I oglądał go w child, to rodzic musi mieć kopię myProp (nie referencję).

Spróbuj tego:

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 }
      }
    }
  }
}

Oraz w html:

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

W takich sytuacjach trzeba być bardzo ostrożnym przy pracy nad złożonymi zbiorami (przechodząc kilka razy)

 7
Author: m.cichacz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-28 09:14:13

Do wiązania dwukierunkowego musisz użyć .modyfikator synchronizacji

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

Więcej Szczegółów...

I musisz użyć właściwości watch w komponencie potomnym, aby nasłuchać i zaktualizować wszelkie zmiany

props: ['myprop'],
  watch: { 
    myprop: function(newVal, oldVal) { // watch it
      console.log('Prop changed: ', newVal, ' | was: ', oldVal)
    }
  }
 5
Author: Md Mahamudul Hasan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-25 02:22:22

Pracuję z obliczoną właściwością typu:

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

Zasoby są w tym przypadku własnością:

props: [ 'resources' ]
 2
Author: Wouter Schoofs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-25 07:05:16

Dla mnie jest to uprzejme rozwiązanie, aby uzyskać jeden konkretny prop (S) zmiany i stworzyć z nim logikę

Użyłbym właściwości props i zmiennych computed do tworzenia logiki po odebraniu zmian

export default {
name: 'getObjectDetail',
filters: {},
components: {},
props: {
  objectDetail: { // <--- we could access to this value with this.objectDetail
    type: Object,
    required: true
  }
},
computed: {
  _objectDetail: {
    let value = false
    // ...
    // if || do || while -- whatever logic
    // insert validation logic with this.objectDetail (prop value)
    value = true
    // ...
    return value 
  }
}

Możemy więc użyć _objectDetail do renderowania html

<span>
  {{ _objectDetail }}
</span>

Lub w jakiejś metodzie:

literallySomeMethod: function() {
   if (this._objectDetail) {
   ....
   }
}
 1
Author: Manuel Alanis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-07 21:23:10

Funkcja watch powinna umieścić w komponencie potomnym. Nie rodzicem.

 0
Author: Cong Nguyen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-25 02:01:49

Możesz użyć trybu zegarka do wykrywania zmian:

Rób wszystko na poziomie atomowym. Więc najpierw sprawdź, czy sama metoda watch jest wywoływana, czy nie, pocieszając coś wewnątrz. Po ustaleniu, że zegarek jest coraz nazywany, rozbić go z logiki biznesowej.
watch: { 
  myProp: function() {
   console.log('Prop changed')
  }
}
 0
Author: Rahul Sharma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-30 10:18:24

Używam właściwości props i zmiennych computed jeśli muszę utworzyć logikę po odebraniu zmian

export default {
name: 'getObjectDetail',
filters: {},
components: {},
props: {
    objectDetail: {
      type: Object,
      required: true
    }
},
computed: {
    _objectDetail: {
        let value = false
        ...

        if (someValidation)
        ...
    }
}

 0
Author: Manuel Alanis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-07 21:08:01

@JoeSchr ma odpowiedź. Oto inny sposób, aby zrobić, jeśli nie chcesz deep: true

 mounted() {
    this.yourMethod();
    // re-render any time a prop changes
    Object.keys(this.$options.props).forEach(key => {
      this.$watch(key, this.yourMethod);
    });
  },
 0
Author: Alvin Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-01 22:28:16

Jeśli myProp jest obiektem, nie może być zmieniony w Normal. więc zegarek nigdy nie zostanie uruchomiony. powodem, dla którego myProp nie może być zmieniany, jest to, że w większości przypadków wystarczy ustawić kilka klawiszy myProp. sam myProp nadal jest tym jedynym. spróbuj oglądać rekwizyty myProp, jak "myProp.a", powinno zadziałać.

 -2
Author: adocking,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-09 03:47:10