'Sahne' değişiklikleri nasıl dinlenir


257

In VueJs 2.0 docs ben dinlerdim herhangi kanca bulamıyorum propsdeğişiklikleri.

VueJ'lerin onPropsUpdated()benzer kancaları var mı ?

Güncelleme

@Wostex'in önerdiği gibi, mülküme çalıştım watchama hiçbir şey değişmedi. Sonra özel bir durumum olduğunu fark ettim:

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

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

myPropÜst bileşenin bileşene aldığını geçiyorum child. O zaman watch: {myProp: ...}çalışmıyor.



1
Vakanızı doğru anladığımdan emin değilim. Tam amacın ne olduğunu açıklayabilir misin? "Bir şey olduğunda, burada bir şeyin katı olmasını istiyorum (nerede?)". Üst prop değerini manuel olarak değiştirmeye mi çalışıyorsunuz? Evet ise, bu tamamen farklı bir durumdur.
Egor Stambakio

@wostex, işte CodePen . Kötü olan şey kalemde çalışıyor olması ...
Amio.io

1
Görüyorum ki, sorun başka bir yerde. Bana kodunu göster, bir göz atarım.
Egor Stambakio

1
Merhaba. İşte: ChannelDetail.vue FacebookPageDetail bileşenini hiçbir yere aktarmazsınız , ancak beyan edin: gist.github.com/zatziky/… Sanırım FacebookChannelDetail.vue, ChannelDetail.vue olarak içe aktarılıyor FacebookPageDetail İyi görünüyor
Egor Stambakio

Yanıtlar:


323

Sen edebilirsiniz watchsahne sahne değişiklikleri üzerine bazı kod çalıştırmasına:

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>


1
Wostex için teşekkürler, ben zaten denedim watch. Örneğiniz nedeniyle davamın biraz farklı olduğunu fark ettim. Sorumu güncelledim.
Amio.io

1
componentWillReceiveProps () gibi görünüyor, örneğin teşekkürler: D
yussan

@ yussan evet, ama takip etmeniz gereken tek bir pervane uygulanır.
Egor Stambakio

1
Saatin cesaretinin kırıldığını biliyorum, çünkü genellikle hesaplanmış bir mülk kullanmak daha iyidir, ancak saatin kullanımıyla ilgili herhangi bir performans sorunu var mı?
SethWhite

1
@SethWhite Gözlemci örüntü kullanılarak Vue'da reaktivitenin nasıl ele alındığını anladığım kadarıyla , gözlemcilerin hesaplanmış veya diğer reaktif verilerden daha az verimli olması gerekmez. Bir özelliğin değerinin birçok değere bağlı olduğu durumlarda, hesaplanan bir pervane, sonucun bağlı olduğu değerlerin her biri için ayrı bir geri izleme ile tek bir işlevi çalıştırır. En yaygın kullanım durumlarında, hesaplanmış bir mülkün istenen sonuca sahip olacağını düşünüyorum.
plong0

83

Bunu denedin mi?

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


7
Bu benim için çalıştı, cevabın olmadığı yerde - belki de bir güncelleme. Teşekkürler BearInBox :)
Grant

2
hemen: gerçek benim için düzeltildi
bazbaz

2
Saati böyle ayarlamak benim için de sabit olan şey, teşekkürler!
adamk22

2
Benim için de çalışıyor. Bu kabul edilen cevap olmalı
titou10

1
benim için de çalıştı, oysa kabul edilen cevap olmadı. +1
Roberto

25

O,

benim durumumda herhangi bir sahne değişecek bir çözüme ihtiyacım vardı, verilerimi tekrar ayrıştırmak gerekiyordu. Ben tüm sahne için ayrı gözetleme yapmaktan bıktım, bu yüzden bunu kullandım:

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

Bu örnekten uzaklaşmanın kilit noktası deep: truesadece $ props izlemekle kalmayıp aynı zamanda örneğinprops.myProp

Bu genişletilmiş saat seçenekleri hakkında daha fazla bilgiyi buradan edinebilirsiniz: https://vuejs.org/v2/api/#vm-watch


İleri ödeme yapmaktan memnunum! İyi şanslar!
JoeSchr

7

Anlamanız gerekir, sahip olduğunuz bileşen hiyerarşisi ve destekleri nasıl geçtiğiniz, kesinlikle durumunuz özeldir ve genellikle geliştiriciler tarafından karşılaşılmaz.

Üst Bileşen -myProp-> Alt Bileşen -myProp-> Torun Bileşeni

MyProp üst bileşende değiştirilirse alt bileşene de yansıtılır .

Ve myProp alt bileşende değiştirilirse torun bileşenine de yansıtılacaktır .

Dolayısıyla myProp üst bileşende değiştirilirse torun bileşenine yansıtılacaktır . (çok uzak çok iyi).

Bu nedenle, hiyerarşiden aşağıya bir şey yapmak zorunda değilsiniz sahne doğası gereği reaktif olacaktır.

Şimdi hiyerarşide yukarı çıkmaktan bahsediyoruz

MyProp grandChild bileşeninde değiştirilirse , alt bileşene yansıtılmaz . Alt öğesinde .sync değiştiricisini kullanmanız ve grandChild bileşeninden olayı yaymanız gerekir.

MyProp alt bileşende değiştirilirse , üst bileşene yansıtılmaz . Üst öğede .sync değiştiricisini kullanmanız ve alt bileşenden emit olayı oluşturmanız gerekir.

MyProp grandChild bileşeninde değiştirilirse , üst bileşene (açıkça) yansıtılmaz . .Sync değiştirici child kullanmalı ve torun bileşeninden olayı emit etmeli, sonra alt bileşendeki prop'i izlemeli ve .sync değiştirici kullanılarak üst bileşen tarafından dinlenen bir değişiklik yayınlamalısınız.

Karışıklığı önlemek için bazı kodlar görelim

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>

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

Ama bundan sonra vue söyleme çığlık uyarıları fark yardımcı olmaz

'Üst bileşen her yeniden oluşturulduğunda değerin üzerine yazılacağından, bir pervaneyi doğrudan değiştirmekten kaçının.'

Daha önce de belirttiğim gibi, geliştiricilerin çoğu bu sorunla karşılaşmıyor, çünkü bu bir anti-desen. Bu yüzden bu uyarıyı alıyorsunuz.

Ama sorununuzu çözmek için (tasarımınıza göre). Yukarıdaki işi etrafta yapmanız gerektiğine inanıyorum (dürüst olmak için kesmek). Hala tasarımınızı yeniden düşünmenizi ve hatalara daha az eğilimli olmasını tavsiye ederim.

Umut ediyorum bu yardım eder.


6

Çözdüğünüzden (ve doğru anladıysam) emin değilim, ama işte benim fikrim:

Üst öğe myProp'u alıyorsa ve alt öğeye geçmesini ve alt öğede izlemesini istiyorsanız, üst öğenin myProp kopyası olması gerekir (başvuru değil).

Bunu dene:

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

ve html biçiminde:

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

aslında bu tür durumlarda karmaşık koleksiyonlar üzerinde çalışırken çok dikkatli olmalısınız (birkaç kez geçerek)


İyi bir fikir. Şu anda doğrulayamıyorum. Vue ile tekrar çalıştığımda kontrol edeceğim.
Amio.io

1
teşekkür ederim @ m.cichacz, aynı hatayı yaptı ve çocuğa bir kopyasını iletme öneriniz sayesinde derhal düzeltildi
undefinederror

4

iki yönlü ciltleme için .sync değiştiricisini kullanmanız gerekir

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

daha fazla detay...

ve değişiklikleri dinlemek ve güncellemek için alt bileşende watch özelliğini kullanmanız gerekir

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

Doğru, bu alt bileşenlerde sahne değişikliklerini izlemenin yeni yolu.
Amio.io

2

Ben bilgisayar gibi bir özellik ile çalışır:

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

Kaynaklar bu durumda bir özelliktir:

props: [ 'resources' ]

1

Benim için bu, belirli bir pervane değişikliklerini almak ve onunla mantık yaratmak için kibar bir çözümdür

Değişiklikleri aldıktan sonra mantık oluşturmak için propsve değişkenler computedözelliklerini kullanırdım

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

Yani, hobml render üzerinde _objectDetail kullanabiliriz

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

veya bazı yöntemlerde:

literallySomeMethod: function() {
   if (this._objectDetail) {
   ....
   }
}

0

Değişiklikleri tespit etmek için izleme modunu kullanabilirsiniz:

Her şeyi atom seviyesinde yapın. Bu nedenle, önce içinde bir şey teselli ederek saat yönteminin kendisinin çağrılıp çağrılmadığını kontrol edin. Saatin kurulduktan sonra, iş mantığınızla parçalayın.

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

0

Değişiklikleri almak için sonra mantık oluşturmam gerekiyorsa propsve değişkenleri kullanıyorumcomputed

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

        if (someValidation)
        ...
    }
}

-1

myProp bir nesne ise, normalde değiştirilemez. bu yüzden saat asla tetiklenmeyecek. myProp'un değiştirilmemesinin nedeni, çoğu durumda myProp'un bazı anahtarlarını ayarlamanızdır. myProp'ın kendisi hala o. "myProp.a" gibi myProp aksesuarlarını izlemeye çalışın.


-1

Saat işlevi, Çocuk bileşenine yerleştirilmelidir. Üst öğe değil.


-1

@JoeSchr'ın iyi bir cevabı var. 'derin: doğru' istemiyorsanız bunu yapmanın başka bir yolu.

 mounted() {
    this.yourMethod();
    // re-render any time a prop changes
    Object.keys(this.$options.props).forEach(key => {
      this.$watch(key, this.yourMethod);
    });
  },
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.