Wie man auf 'Requisiten'-Änderungen wartet

257

In den VueJs 2.0-Dokumenten kann ich keine Hooks finden, die propsÄnderungen abhören würden.

Hat VueJs solche Haken wie onPropsUpdated()oder ähnlich?

Aktualisieren

Wie @wostex vorgeschlagen hat, habe ich versucht, watchmein Eigentum, aber nichts hat sich geändert. Dann wurde mir klar, dass ich einen Sonderfall habe:

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

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

Ich übergebe, myPropdass die übergeordnete Komponente an die childKomponente empfängt . Dann watch: {myProp: ...}funktioniert das nicht.

Amio.io
quelle
1
Ich bin mir nicht sicher, ob ich Ihren Fall richtig verstehe. Können Sie erklären, was Ihr genaues Ziel ist? "Wenn etwas passiert, möchte ich, dass hier etwas passiert (wo?)". Versuchen Sie, den übergeordneten Requisitenwert manuell zu ändern? Wenn ja, ist dies ein völlig anderer Fall.
Egor Stambakio
@wostex, hier ist der CodePen . Das Schlimme ist, dass es im Stift funktioniert ...
Amio.io
1
Ich sehe, das Problem ist woanders. Zeigen Sie mir Ihren Code, ich werde einen Blick darauf werfen.
Egor Stambakio
1
Hallo. Hier: ChannelDetail.vue Sie importieren keine FacebookPageDetail-Komponente, sondern deklarieren sie: gist.github.com/zatziky/… Ich denke, es sollte FacebookChannelDetail.vue sein, das als FacebookPageDetail in ChannelDetail.vue importiert wird. Ansonsten sieht es gut aus
Egor Stambakio

Antworten:

321

Sie können watchRequisiten verwenden, um bei Änderungen der Requisiten Code auszuführen:

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>

Egor Stambakio
quelle
1
Danke für wostex, ich habe es schon versucht watch. Aufgrund Ihres Beispiels habe ich festgestellt, dass mein Fall etwas anders ist. Ich habe meine Frage aktualisiert.
Amio.io
1
Sehen Sie, es sieht aus wie componentWillReceiveProps (), danke zum Beispiel: D
yussan
@yussan ja, aber es wird auf eine einzelne Requisite angewendet, die Sie im Auge behalten müssen.
Egor Stambakio
1
Ich weiß, dass Uhr nicht empfohlen wird, da es normalerweise besser ist, eine berechnete Eigenschaft zu verwenden. Gibt es jedoch Leistungsprobleme bei der Verwendung von Uhr?
SethWhite
1
@SethWhite Soweit ich weiß, wie Reaktivität in Vue mithilfe des Beobachtermusters gehandhabt wird, sind Beobachter nicht unbedingt weniger effizient als berechnete oder andere reaktive Daten. In Fällen, in denen der Wert einer Eigenschaft von vielen Werten abhängt, führt eine berechnete Requisite eine einzelne Funktion gegenüber einem separaten Überwachungsrückruf für jeden der Werte aus, von denen das Ergebnis abhängt. Ich denke, in den meisten gängigen Anwendungsfällen hätte eine berechnete Eigenschaft das gewünschte Ergebnis.
plong0
83

Hast du das versucht?

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

BearInBox
quelle
7
Das hat bei mir funktioniert, wo die Antwort nicht funktioniert hat - vielleicht ist es ein Update. Danke BearInBox :)
Grant
2
Sofort: True hat es für mich
behoben
2
Das Einstellen der Uhr ist das, was es auch für mich behoben hat, danke!
Adamk22
2
Funktioniert auch bei mir. Dies sollte die akzeptierte Antwort sein
titou10
1
arbeitete auch für mich, während die akzeptierte Antwort nicht funktionierte. +1
Roberto
25

Er,

In meinem Fall brauchte ich eine Lösung, bei der ich meine Daten immer wieder analysieren musste, wenn sich Requisiten änderten. Ich war es leid, für alle meine Requisiten einen separaten Beobachter zu machen, also benutzte ich Folgendes:

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

Der wichtigste Punkt, den Sie aus diesem Beispiel entfernen sollten, ist die Verwendung deep: true, damit nicht nur $ props, sondern auch verschachtelte Werte wie zprops.myProp

Weitere Informationen zu diesen erweiterten Überwachungsoptionen finden Sie hier: https://vuejs.org/v2/api/#vm-watch

JoeSchr
quelle
Freut mich, es vorwärts zu zahlen! Viel Glück!
JoeSchr
7

Sie müssen verstehen, welche Komponentenhierarchie Sie haben und wie Sie Requisiten übergeben. Auf jeden Fall ist Ihr Fall etwas Besonderes und wird von den Entwicklern normalerweise nicht angetroffen.

Übergeordnete Komponente -myProp-> Untergeordnete Komponente -myProp-> Enkelkind-Komponente

Wenn myProp in der übergeordneten Komponente geändert wird, wird dies auch in der untergeordneten Komponente angezeigt .

Und wenn myProp in der untergeordneten Komponente geändert wird, wird dies auch in der Enkelkomponente wiedergegeben .

Wenn also myProp in der übergeordneten Komponente geändert wird, wird es in der Enkelkomponente wiedergegeben . (So ​​weit, ist es gut).

Daher müssen Sie in der gesamten Hierarchie nichts tun. Requisiten sind von Natur aus reaktiv.

Ich spreche jetzt davon, in der Hierarchie aufzusteigen

Wenn myProp in der grandChild-Komponente geändert wird , wird es nicht wiedergegeben . Sie müssen den Modifikator .sync in child verwenden und ein Ereignis von der grandChild-Komponente ausgeben.

Wenn myProp in der untergeordneten Komponente geändert wird , wird es nicht in der übergeordneten Komponente wiedergegeben. Sie müssen den Modifikator .sync im übergeordneten Element verwenden und ein Ereignis von der untergeordneten Komponente ausgeben.

Wenn myProp in der grandChild-Komponente geändert wird , wird es (offensichtlich) nicht in der übergeordneten Komponente wiedergegeben. Sie müssen den untergeordneten Modifikator .sync verwenden und ein Ereignis von der Enkelkomponente ausgeben, dann die Requisite in der untergeordneten Komponente beobachten und ein Ereignis bei Änderung ausgeben, das von der übergeordneten Komponente mit dem Modifikator .sync abgehört wird.

Sehen wir uns einen Code an, um Verwirrung zu vermeiden

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>

Enkelkind

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

Aber danach werden Sie die schreienden Warnungen des Vue-Sprichworts nicht mehr bemerken

'Vermeiden Sie es, eine Requisite direkt zu mutieren, da der Wert bei jedem erneuten Rendern der übergeordneten Komponente überschrieben wird.'

Wie ich bereits erwähnt habe, stoßen die meisten Entwickler nicht auf dieses Problem, da es sich um ein Anti-Pattern handelt. Deshalb erhalten Sie diese Warnung.

Aber um Ihr Problem zu lösen (entsprechend Ihrem Design). Ich glaube, Sie müssen die oben genannten Probleme umgehen (Hack, um ehrlich zu sein). Ich empfehle Ihnen dennoch, Ihr Design zu überdenken und zu machen, ist weniger anfällig für Fehler.

Ich hoffe, es hilft.

Der Beobachter
quelle
6

Ich bin mir nicht sicher, ob Sie es gelöst haben (und ob ich es richtig verstehe), aber hier ist meine Idee:

Wenn Eltern myProp empfangen und möchten, dass es an Kind übergeben und in Kind angezeigt wird, muss Eltern über eine Kopie von myProp verfügen (keine Referenz).

Versuche dies:

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

und in HTML:

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

Eigentlich muss man sehr vorsichtig sein, wenn man in solchen Situationen an komplexen Sammlungen arbeitet (einige Male weitergegeben).

m.cichacz
quelle
Gute Idee. Ich kann es im Moment nicht einfach validieren. Wenn ich wieder mit vue arbeite, werde ich es überprüfen.
Amio.io
1
danke @ m.cichacz, habe den gleichen Fehler gemacht und umgehend behoben, dank Ihres Vorschlags, eine Kopie an das Kind weiterzugeben
undefinederror
4

Für die bidirektionale Bindung müssen Sie den Modifikator .sync verwenden

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

mehr Details...

und Sie müssen die watch-Eigenschaft in der untergeordneten Komponente verwenden, um Änderungen abzuhören und zu aktualisieren

props: ['myprop'],
  watch: { 
    myprop: function(newVal, oldVal) { // watch it
      console.log('Prop changed: ', newVal, ' | was: ', oldVal)
    }
  }
Md Mahamudul Hasan
quelle
Dies ist die neue Methode, um nach Änderungen an Requisiten in untergeordneten Komponenten zu suchen.
Amio.io
2

Ich arbeite mit einer berechneten Eigenschaft wie:

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

Resources ist in diesem Fall eine Eigenschaft:

props: [ 'resources' ]
Wouter Schoofs
quelle
1

Für mich ist dies eine höfliche Lösung, um bestimmte Requisitenänderungen zu erhalten und damit Logik zu erstellen

Ich würde propsund Variablen computedEigenschaften verwenden, um Logik zu erstellen, nachdem die Änderungen empfangen wurden

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

Wir könnten also _objectDetail für HTML-Rendering verwenden

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

oder in irgendeiner Methode:

literallySomeMethod: function() {
   if (this._objectDetail) {
   ....
   }
}
Manuel Alanis
quelle
0

Sie können den Überwachungsmodus verwenden, um Änderungen zu erkennen:

Mach alles auf atomarer Ebene. Überprüfen Sie also zuerst, ob die Überwachungsmethode selbst aufgerufen wird oder nicht, indem Sie etwas im Inneren trösten. Sobald festgestellt wurde, dass die Uhr aufgerufen wird, zerschlagen Sie sie mit Ihrer Geschäftslogik.

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

Ich verwende Eigenschaften propsund Variablen, computedwenn ich nachher Logik erstellen muss, um die Änderungen zu erhalten

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

        if (someValidation)
        ...
    }
}
Manuel Alanis
quelle
-1

Wenn myProp ein Objekt ist, kann es normalerweise nicht geändert werden. Die Uhr wird also niemals ausgelöst. Der Grund, warum myProp nicht geändert wird, ist, dass Sie in den meisten Fällen nur einige Schlüssel von myProp festlegen. Der myProp selbst ist immer noch derjenige. Versuchen Sie, Requisiten von myProp wie "myProp.a" anzusehen, es sollte funktionieren.

adocking
quelle
-1

Die Überwachungsfunktion sollte in der untergeordneten Komponente platziert werden. Nicht Eltern.

Cong Nguyen
quelle
-1

@ JoeSchr hat eine gute Antwort. Hier ist eine andere Möglichkeit, dies zu tun, wenn Sie nicht "tief: wahr" wollen.

 mounted() {
    this.yourMethod();
    // re-render any time a prop changes
    Object.keys(this.$options.props).forEach(key => {
      this.$watch(key, this.yourMethod);
    });
  },
Alvin Smith
quelle