Vue.js 2'de props'ı başlangıç ​​verileri olarak geçirmenin doğru yolu nedir?


108

Bu yüzden, bir Vue bileşenine props aktarmak istiyorum, ancak bu props'ların gelecekte bu bileşenin içinden değişmesini bekliyorum, örneğin, AJAX kullanarak o Vue bileşenini içeriden güncellediğimde. Bu yüzden sadece bileşenin ilklendirilmesi içindir.

Benim cars-listVue I başlangıç özellikleri olan sahne geçen yapı elemanı 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>

Bunu hemen yapmak yolu içim o single-carbileşenin ben atıyorum this.initialPropertiesbenim için this.data.propertiesilgili created()başlatma kanca. Ve işe yarıyor ve reaktif.

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

Ama bununla ilgili sorunum, bunu yapmanın doğru bir yolu olup olmadığını bilmemem mi? Yol boyunca bana bazı sorunlara neden olmaz mı? Yoksa bunu yapmanın daha iyi bir yolu var mı?


15
Her: Bu bence Vue hakkında en kafa karıştırıcı şey dataolduğunu two-waybağlanmış, ancak geçemez databileşenlerine, geçtiğiniz propsama alınan değiştiremezsiniz propsne de dönüştürmek propsiçin data. Sonra ne? Öğrendiğim bir şey, propsaşağı inip olayları tetiklemeniz gerektiğiydi . Yani, bileşen propsaldığını değiştirmek isterse , bir olay çağırmalı ve "yeniden gönderilmelidir". Ama sonra one-waytam olarak React gibi bir bağlama ile kaldınız ve datao zaman için kullanımını göremiyorum . Oldukça kafa karıştırıcı.
André Pena

1
Veriler, öncelikle bileşenin özel kullanımına yöneliktir. Bileşen bağlamında üzerine yerleştirilen her şey reaktiftir ve bağlanabilir. Props ile kavram, değerleri bir bileşene aktarmak, ancak bileşenin, geçirilen bir değeri değiştirerek üst öğedeki durum değişikliklerini sessizce tanıtmasını önlemektir. Belirttiğiniz gibi bir olayda açıklığa kavuşturmak daha iyidir. Bu, Vue 1.0'dan 2.0'a bir felsefe değişikliğiydi.
David K. Hess

Bugün burada bir başlık
bgraves

Yanıtlar:


112

Bu https://github.com/vuejs/vuejs.org/pull/567 sayesinde cevabı şimdi biliyorum.

Yöntem 1

İlk pervaneyi doğrudan verilere aktarın. Güncellenen dokümanlardaki örnek gibi:

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

Ancak, aktarılan prop, ana bileşen durumunda kullanılan bir nesne veya dizi ise, bu prop üzerinde yapılacak herhangi bir değişiklik, üst bileşen durumunda değişikliğe yol açacaktır.

Uyarı : bu yöntem önerilmez. Bileşenlerinizi öngörülemez hale getirecektir. Alt bileşenlerden üst verileri ayarlamanız gerekiyorsa, Vuex gibi durum yönetimini veya "v-modelini" kullanın. https://vuejs.org/v2/guide/components.html#Using-v-model-on-Components

Yöntem 2

İlk prop'unuz bir nesne veya diziyse ve alt durumdaki değişikliklerin üst duruma yayılmasını istemiyorsanız, örneğin Vue.util.extend[1] 'i doğrudan alt verilere işaret etmek yerine propların bir kopyasını yapmak için kullanın, örneğin:

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

Yöntem 3

Nesneleri klonlamak için yayma operatörünü de kullanabilirsiniz. Igor yanıtında daha fazla ayrıntı: https://stackoverflow.com/a/51911118/3143704

Ancak, yayılma operatörlerinin eski tarayıcılarda desteklenmediğini ve daha iyi uyumluluk için, örneğin kullanarak kodu aktarmanız gerekeceğini unutmayın babel.

Dipnotlar

[1] Bunun dahili bir Vue yardımcı programı olduğunu ve yeni sürümlerle değişebileceğini unutmayın. Bu pervaneyi kopyalamak için başka yöntemler kullanmak isteyebilirsiniz, bkz. " Bir JavaScript nesnesini nasıl doğru bir şekilde klonlarım? ".

Test ettiğim kemanım: https://jsfiddle.net/sm4kx7p9/3/


1
öyleyse, değişikliklerin ana bileşene yayılmasına izin verilebilir mi?
igor

1
@igor şahsen elimden geldiğince bundan kaçınmaya çalışırım. Bileşenlerinizi öngörülemez hale getirecektir. Üst bileşendeki değişiklikleri almanın daha iyi bir yolu, alt bileşenden üst bileşene değişiklikleri $ yaydığınız "v-modeli" yöntemini kullanmaktır. vuejs.org/v2/guide/components.html#Using-v-model-on-Components
Dominik Serafin

evet ama ya derin nesneler? derin kopyalamalı mıyım? Derin nesneler kullanmamak için bileşenlerimi yeniden tasarlamalı mıyım? Yani bir destek: { ok: 1, notOk: { meh: 2 } }önceki klonlama yöntemlerinden herhangi biriyle dahili bir veriye ayarlanırsa, yine de notOk.meh
propu

2
Mükemmel soru ve cevap için teşekkürler @DominikSerafin. Bu, Vue.js'nin aşil iyileşmesini mükemmel bir şekilde göstermektedir. Çerçeve olarak bileşenlemeyi çok iyi idare eder, ancak verileri bilgisayarlar arasında aktarmak önemli bir PITA'dır. Yaratılan isimlendirme kabusuna bakın. Bu yüzden şimdi tüm sahne donanımlarımı kompozisyonumda kullanabilmek için önek yapmam gerekiyor initial. dataHerhangi bir bilgisayara çağrılan bir pervane aktarabilirsek ve yerelleştirilmiş verileri tüm bu initialPropNameçılgınlık olmadan otomatik olarak yaymasını sağlayabilirsek çok daha temiz olurdu .
AJB

1
@DominikSerafin Ne dediğini duyuyorum ve yanlış değilsin. Ancak Vue.js kullanarak bir form oluşturucu uygulaması yazın ve ne demek istediğimi çabucak anlayacaksınız. Aslında, veri paylaşma tekniğimi tüm veriler prop --> comp.dataiçin Vue-Stash kullanmaktan değiştirme sürecindeyim (veya Vuex de işe yarardı). Ama şimdi , "modern" JS çerçeveleri bana fikirlerini empoze etmeden önce yaptığım gibi verilerimi nesneden geri döndürüyorum. Bu nedenle şu soruyu akla getiriyor: comp.data özelliğinin anlamı nedir? window
AJB

29

@ Dominik-serafin'in cevabına eşlik eden:

Bir nesneyi geçirmeniz durumunda, onu yayma işleci (ES6 Sözdizimi) kullanarak kolayca klonlayabilirsiniz:

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

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

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

Ancak en önemlisi, opt. 2, hesaplanan bir değer veya bundan daha fazla bir zaman uyumsuz değer geçirmeniz durumunda. Aksi takdirde yerel değer güncellenmeyecektir.

Demo:

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/vue@2.5.17/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/


Hey @ igor-parra, yinelenen yanıtlar göndermişsiniz gibi görünüyor. Ayrıca, yayılma operatörünün tüm tarayıcılarda desteklenmediğini ve daha iyi uyumluluk için dönüştürme adımına ihtiyaç duyabileceğini belirtmek iyi olabilir. Aksi takdirde harika görünüyor - bu alternatif yöntemi eklediğiniz için teşekkürler!
Dominik Serafin

@ dominik-serafin Evet, haklısın, ES6'ya bir referans ekledim. Web paketi tabanlı uygulamalarda, modern javascript'i tam olarak kullanmak için önceden yapılandırılmış babel'e sahip olmak çok kolaydır.
Igor Parra

recordLocal: [...this.record](benim vaka kaydımda bir dizi) benim için çalışmadı - vue bileşenini yükledikten ve inceledikten sonra record, öğeleri içeriyor ve recordLocalboş bir diziydi.
Hıristiyan

COMPUTED özelliği olsa da kullandığımda iyi gidiyor, benim için veri içinde ayarlamaya çalıştığımda çalışmıyor = (... Ama onu kullanıyorumcomputed
felipe muner

Dikkatli ol. Yayılma operatörü yalnızca yüzeysel klonlar olduğundan, nesneler veya diziler içeren nesneler için yeni bir kopya almak yerine yine de işaretçileri kopyalayacaksınız. Lodash'tan CloneDeep kullanıyorum.
Cindy Conway

14

Bunu doğru yaptığına inanıyorum çünkü belgelerde belirtildiği gibi.

Pervanenin başlangıç ​​değerini başlangıç ​​değeri olarak kullanan yerel bir veri özelliği tanımlama

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


4
Değere göre geçişli aksesuarlar için bu gayet iyi. Bu durumda bu bir nesnedir, bu nedenle değiştirmek ebeveyni etkileyecektir. Bu sayfadan: "JavaScript'teki nesnelerin ve dizilerin başvuruya göre aktarıldığına dikkat edin; bu nedenle, pervane bir dizi veya nesneyse, nesnenin veya dizinin alt bileşen içinde mutasyona uğratılması ana durumu etkileyecektir."
Jake

Bu benim için çalışıyor ve açıkça belgeleniyor. Yukarıdaki yanıttaki bu satır vue belgeleriyle çelişiyor "Uyarı: bu yöntem tavsiye edilmez. Bileşenlerinizi öngörülemez hale getirecektir. Alt bileşenlerden ana verileri ayarlamanız gerekiyorsa ya Vuex gibi durum yönetimini kullanın ya da "v-model". "
Nathaniel Rink

2
Bu yüzden 4 yıl ve yüzlerce saatlik öğrenme eğrisinden sonra, windownesneden sıçramaya başladığım yere geri döndüm .
AJB
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.