Gambaran
Di Vue.js 2.x, tidak model.sync
akan digunakan lagi .
Jadi, apa cara yang tepat untuk berkomunikasi antar komponen saudara di Vue.js 2.x ?
Latar Belakang
Seperti yang saya pahami Vue 2.x, metode yang disukai untuk komunikasi saudara adalah menggunakan toko atau bus acara .
Menurut Evan (pencipta Vue):
Perlu juga disebutkan bahwa "melewatkan data antar komponen" umumnya merupakan ide yang buruk, karena pada akhirnya aliran data menjadi tidak dapat dilacak dan sangat sulit untuk di-debug.
Jika sepotong data perlu dibagikan oleh banyak komponen, pilih penyimpanan global atau Vuex .
Dan:
.once
dan.sync
tidak digunakan lagi. Alat peraga sekarang selalu turun satu arah. Untuk menghasilkan efek samping dalam lingkup induk, sebuah komponen perlu secara eksplisitemit
sebuah peristiwa daripada mengandalkan pengikatan implisit.
Jadi, Evan menyarankan untuk menggunakan $emit()
dan $on()
.
Kekhawatiran
Yang membuat saya khawatir adalah:
- Masing
store
- masing danevent
memiliki visibilitas global (perbaiki saya jika saya salah); - Terlalu boros untuk membuat toko baru untuk setiap komunikasi kecil;
Yang saya inginkan adalah beberapa ruang lingkup events
atau stores
visibilitas untuk komponen saudara kandung. (Atau mungkin saya tidak memahami gagasan di atas.)
Pertanyaan
Jadi, bagaimana cara yang benar untuk berkomunikasi antar komponen sibling?
sumber
$emit
dikombinasikan denganv-model
meniru.sync
. saya pikir Anda harus pergi ke jalanJawaban:
Dengan Vue 2.0, saya menggunakan mekanisme eventHub seperti yang ditunjukkan dalam dokumentasi .
Tentukan hub acara terpusat.
Sekarang dalam komponen Anda, Anda dapat mengeluarkan acara dengan
Dan untuk mendengarkan yang Anda lakukan
Pembaruan Silakan lihat jawaban oleh @alex , yang menjelaskan solusi yang lebih sederhana.
sumber
this.$root.$emit()
this.$root.$on()
Anda bahkan dapat membuatnya lebih pendek dan menggunakan instance root
Vue
sebagai Event Hub global:Komponen 1:
Komponen 2:
sumber
Jenis komunikasi
Saat mendesain aplikasi Vue (atau pada kenyataannya, aplikasi berbasis komponen apa pun), ada tipe komunikasi berbeda yang bergantung pada masalah mana yang kita hadapi dan mereka memiliki saluran komunikasinya sendiri.
Logika bisnis: mengacu pada semua yang spesifik untuk aplikasi Anda dan tujuannya.
Logika presentasi: segala sesuatu yang berinteraksi dengan pengguna atau yang dihasilkan dari interaksi dari pengguna.
Kedua masalah ini terkait dengan jenis komunikasi berikut:
Setiap tipe harus menggunakan saluran komunikasi yang tepat.
Saluran komunikasi
Saluran adalah istilah longgar yang akan saya gunakan untuk merujuk pada implementasi konkret untuk bertukar data di sekitar aplikasi Vue.
Properti: Logika presentasi Orang Tua-Anak
Saluran komunikasi paling sederhana di Vue for direct Parent-Child komunikasi . Ini sebagian besar harus digunakan untuk meneruskan data yang berkaitan dengan logika presentasi atau kumpulan data terbatas di bawah hierarki.
Referensi dan metode: Presentasi anti-pola
Jika tidak masuk akal menggunakan prop untuk membiarkan anak menangani kejadian dari induk, menyiapkanref
komponen anak dan memanggil metodenya sudah cukup.Jangan lakukan itu, itu anti-pola. Pikirkan kembali arsitektur komponen dan aliran data Anda. Jika Anda menemukan diri Anda ingin memanggil metode pada komponen anak dari orang tua, mungkin inilah saatnya untuk mengangkat status atau mempertimbangkan cara lain yang dijelaskan di sini atau di jawaban lain.
Events: Logika presentasi Child-Parent
$emit
dan$on
. Saluran komunikasi paling sederhana untuk komunikasi langsung Child-Parent. Sekali lagi, harus digunakan untuk logika presentasi.Bus acara
Sebagian besar jawaban memberikan alternatif yang baik untuk bus acara, yang merupakan salah satu saluran komunikasi yang tersedia untuk komponen yang jauh, atau apa pun sebenarnya.
Ini bisa menjadi berguna saat meneruskan props ke semua tempat dari jauh ke bawah hingga komponen anak yang sangat bertingkat, dengan hampir tidak ada komponen lain yang membutuhkan ini di antaranya. Gunakan secukupnya untuk data yang dipilih dengan cermat.
Hati-hati: Pembuatan komponen selanjutnya yang mengikat dirinya sendiri ke bus acara akan terikat lebih dari satu kali - menyebabkan beberapa penangan terpicu dan bocor. Saya pribadi tidak pernah merasakan kebutuhan akan bus acara di semua aplikasi satu halaman yang telah saya rancang sebelumnya.
Berikut ini menunjukkan bagaimana kesalahan sederhana menyebabkan kebocoran di mana
Item
komponen masih terpicu meskipun dihapus dari DOM.Tampilkan cuplikan kode
Ingatlah untuk menghapus listener di
destroyed
hook siklus proses.Toko terpusat (logika bisnis)
Vuex adalah cara terbaik untuk menggunakan Vue untuk manajemen negara . Ini menawarkan lebih dari sekadar acara dan siap untuk aplikasi skala penuh.
Dan sekarang Anda bertanya :
Ini benar-benar bersinar ketika:
Jadi komponen Anda benar-benar dapat fokus pada hal-hal yang seharusnya, mengelola antarmuka pengguna.
Ini tidak berarti bahwa Anda tidak dapat menggunakannya untuk logika komponen, tetapi saya akan memperluas logika itu ke modul Vuex dengan namespace hanya dengan status UI global yang diperlukan.
Untuk menghindari kekacauan besar dalam segala hal dalam keadaan global, penyimpanan harus dipisahkan dalam beberapa modul dengan namespace.
Jenis komponen
Untuk mengatur semua komunikasi ini dan untuk memudahkan penggunaan kembali, kita harus memikirkan komponen sebagai dua jenis yang berbeda.
Sekali lagi, ini tidak berarti bahwa komponen generik harus digunakan kembali atau wadah khusus aplikasi tidak dapat digunakan kembali, tetapi mereka memiliki tanggung jawab yang berbeda.
Penampung khusus aplikasi
Ini hanyalah komponen Vue sederhana yang membungkus komponen Vue lainnya (generik atau wadah khusus aplikasi lainnya). Di sinilah komunikasi penyimpanan Vuex harus terjadi dan wadah ini harus berkomunikasi melalui cara lain yang lebih sederhana seperti alat peraga dan pendengar acara.
Penampung ini bahkan bisa saja tidak memiliki elemen DOM asli sama sekali dan membiarkan komponen generik menangani template dan interaksi pengguna.
Di sinilah pelingkupan terjadi. Sebagian besar komponen tidak tahu tentang penyimpanan dan komponen ini harus (kebanyakan) menggunakan satu modul penyimpanan berspasi nama dengan satu set terbatas
getters
danactions
diterapkan dengan pembantu pengikat Vuex yang disediakan .Komponen umum
Ini harus menerima data mereka dari alat peraga, membuat perubahan pada data lokal mereka sendiri, dan mengeluarkan kejadian sederhana. Sebagian besar waktu, mereka seharusnya tidak tahu bahwa toko Vuex ada.
Mereka juga bisa disebut kontainer karena tanggung jawab mereka bisa untuk mengirim ke komponen UI lainnya.
Komunikasi saudara
Jadi, setelah semua ini, bagaimana seharusnya kita berkomunikasi antara dua komponen bersaudara?
Lebih mudah dipahami dengan sebuah contoh: katakanlah kita memiliki kotak input dan datanya harus dibagikan di seluruh aplikasi (saudara kandung di tempat berbeda di pohon) dan dipertahankan dengan backend.
Dimulai dengan skenario terburuk , komponen kami akan menggabungkan presentasi dan logika bisnis .
Untuk memisahkan kedua masalah ini, kita harus membungkus komponen kita dalam wadah khusus aplikasi dan menyimpan logika presentasi ke dalam komponen masukan generik kita.
Komponen input kita sekarang dapat digunakan kembali dan tidak mengetahui tentang backend maupun siblingnya.
Container khusus aplikasi kami sekarang dapat menjadi jembatan antara logika bisnis dan komunikasi presentasi.
Karena tindakan penyimpanan Vuex berhubungan dengan komunikasi backend, container kita di sini tidak perlu mengetahui tentang axios dan backend.
sumber
Oke, kita bisa berkomunikasi antar saudara lewat orang tua menggunakan
v-on
event.Mari kita asumsikan bahwa kita ingin mengupdate
Details
komponen ketika kita mengklik beberapa elemen diList
.di
Parent
:Template:
Sini:
v-on:select-item
itu sebuah acara, yang akan dipanggil dalamList
komponen (lihat di bawah);setSelectedItem
itu adalahParent
metode untuk memperbaruiselectedModel
;JS:
Masuk
List
:Template:
JS:
Sini:
this.$emit('select-item', item)
akan mengirimkan barang melaluiselect-item
langsung di orang tua. Dan orang tua akan mengirimkannya keDetails
tampilansumber
Apa yang biasanya saya lakukan jika saya ingin "meretas" pola komunikasi normal di Vue, khususnya sekarang yang
.sync
sudah usang, adalah membuat EventEmitter sederhana yang menangani komunikasi antar komponen. Dari salah satu proyek terbaru saya:Dengan
Transmitter
objek ini, Anda dapat melakukannya, dalam komponen apa pun:Dan untuk membuat komponen "penerima":
Sekali lagi, ini untuk penggunaan yang sangat spesifik. Jangan mendasarkan seluruh aplikasi Anda pada pola ini, gunakan sesuatu seperti itu
Vuex
.sumber
vuex
, tetapi sekali lagi, haruskah saya membuat toko vuex untuk setiap komunikasi kecil?vuex
ya, lakukanlah. Gunakan.Cara menangani komunikasi antar saudara tergantung pada situasinya. Tapi pertama-tama saya ingin menekankan bahwa pendekatan bus acara global akan dihentikan di Vue 3 . Lihat RFC ini . Oleh karena itu mengapa saya memutuskan untuk menulis jawaban baru.
Pola Leluhur Umum Terendah (atau "LCA")
Untuk kasus sederhana, saya sangat menyarankan menggunakan pola Leluhur Umum Terendah (juga dikenal sebagai "data turun, peristiwa naik"). Pola ini mudah dibaca, diterapkan, diuji, dan di-debug.
Intinya, ini berarti jika dua komponen perlu berkomunikasi, letakkan status bersama mereka di komponen terdekat yang sama-sama berbagi sebagai leluhur. Meneruskan data dari komponen induk ke komponen anak melalui props, dan meneruskan informasi dari anak ke induk dengan memancarkan sebuah peristiwa (lihat contohnya di bagian bawah jawaban ini).
Untuk contoh yang dibuat-buat, dalam aplikasi email, jika komponen "Kepada" perlu berinteraksi dengan komponen "badan pesan", status interaksi tersebut dapat berada di induknya (mungkin disebut komponen
email-form
). Anda mungkin memiliki prop diemail-form
disebutaddressee
sehingga tubuh pesan dapat secara otomatis tambahkanDear {{addressee.name}}
ke email berdasarkan alamat email penerima.LCA menjadi berat jika komunikasi harus menempuh jarak jauh dengan banyak komponen perantara. Saya sering merujuk rekan kerja ke posting blog yang luar biasa ini . (Abaikan fakta bahwa contohnya menggunakan Ember; idenya dapat diterapkan di banyak kerangka kerja UI.)
Pola Penampung Data (misalnya, Vuex)
Untuk kasus atau situasi kompleks di mana komunikasi orang tua-anak akan melibatkan terlalu banyak perantara, gunakan Vuex atau teknologi wadah data yang setara. Jika sesuai, gunakan modul dengan spasi nama .
Misalnya, mungkin masuk akal untuk membuat namespace terpisah untuk kumpulan komponen yang kompleks dengan banyak interkoneksi, seperti komponen kalender berfitur lengkap.
Publikasikan / Berlangganan (Bus Acara) Pola
Jika pola event bus (atau "publish / subscribe") lebih sesuai untuk kebutuhan Anda, tim inti Vue sekarang merekomendasikan menggunakan perpustakaan pihak ketiga seperti mitt . (Lihat RFC yang direferensikan di paragraf 1.)
Bonus bertele-tele dan kode
Berikut adalah contoh dasar dari solusi Leluhur Umum Terendah untuk komunikasi saudara-ke-saudara, yang diilustrasikan melalui permainan whack-a-mole .
Pendekatan yang naif mungkin berpikir, "tahi lalat 1 harus memberitahu tahi lalat 2 untuk muncul setelah dihantam". Tetapi Vue melarang pendekatan semacam ini, karena ia ingin kita berpikir dalam kerangka struktur pohon .
Ini mungkin hal yang sangat bagus. Aplikasi non-sepele tempat node berkomunikasi secara langsung satu sama lain di seluruh pohon DOM akan sangat sulit untuk di-debug tanpa semacam sistem akuntansi (seperti yang disediakan Vuex). Selain itu, komponen yang menggunakan "data turun, peristiwa naik" cenderung menunjukkan kopling rendah dan kegunaan kembali yang tinggi — keduanya merupakan sifat yang sangat diinginkan yang membantu aplikasi berskala besar.
Dalam contoh ini, ketika tahi lalat dipukul, itu memancarkan peristiwa. Komponen pengelola game memutuskan apa status baru aplikasi tersebut, dan dengan demikian mol saudara tahu apa yang harus dilakukan secara implisit setelah Vue merender ulang. Ini adalah contoh “nenek moyang terendah” yang agak sepele.
sumber