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:
- Status aplikasi
- Orang tua-anak
- Anak-orang tua
- Saudara kandung
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, menyiapkan ref
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.
// A component that binds to a custom 'update' event.
var Item = {
template: `<li>{{text}}</li>`,
props: {
text: Number
},
mounted() {
this.$root.$on('update', () => {
console.log(this.text, 'is still alive');
});
},
};
// Component that emits events
var List = new Vue({
el: '#app',
components: {
Item
},
data: {
items: [1, 2, 3, 4]
},
updated() {
this.$root.$emit('update');
},
methods: {
onRemove() {
console.log('slice');
this.items = this.items.slice(0, -1);
}
}
});
<script src="https://unpkg.com/vue@2.5.17/dist/vue.min.js"></script>
<div id="app">
<button type="button" @click="onRemove">Remove</button>
<ul>
<item v-for="item in items" :key="item" :text="item"></item>
</ul>
</div>
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 :
[S] haruskah saya membuat toko vuex untuk setiap komunikasi kecil?
Ini benar-benar bersinar ketika:
- berurusan dengan logika bisnis Anda,
- berkomunikasi dengan backend (atau lapisan persistensi data apa pun, seperti penyimpanan lokal)
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.
- Penampung khusus aplikasi
- Komponen umum
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.
cakupan entah bagaimana events
atau stores
visibilitas untuk komponen saudara
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
dan actions
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 .
// MyInput.vue
<template>
<div class="my-input">
<label>Data</label>
<input type="text"
:value="value"
:input="onChange($event.target.value)">
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
value: "",
};
},
mounted() {
this.$root.$on('sync', data => {
this.value = data.myServerValue;
});
},
methods: {
onChange(value) {
this.value = value;
axios.post('http://example.com/api/update', {
myServerValue: value
})
.then((response) => {
this.$root.$emit('update', response.data);
});
}
}
}
</script>
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.
// MyInput.vue
// the template is the same as above
<script>
export default {
props: {
initial: {
type: String,
default: ""
}
},
data() {
return {
value: this.initial,
};
},
methods: {
onChange(value) {
this.value = value;
this.$emit('change', value);
}
}
}
</script>
Container khusus aplikasi kami sekarang dapat menjadi jembatan antara logika bisnis dan komunikasi presentasi.
// MyAppCard.vue
<template>
<div class="container">
<card-body>
<my-input :initial="serverValue" @change="updateState"></my-input>
<my-input :initial="otherValue" @change="updateState"></my-input>
</card-body>
<card-footer>
<my-button :disabled="!serverValue || !otherValue"
@click="saveState"></my-button>
</card-footer>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
import { NS, ACTIONS, GETTERS } from '@/store/modules/api';
import { MyButton, MyInput } from './components';
export default {
components: {
MyInput,
MyButton,
},
computed: mapGetters(NS, [
GETTERS.serverValue,
GETTERS.otherValue,
]),
methods: mapActions(NS, [
ACTIONS.updateState,
ACTIONS.updateState,
])
}
</script>
Karena tindakan penyimpanan Vuex berhubungan dengan komunikasi backend, container kita di sini tidak perlu mengetahui tentang axios dan backend.
$emit
dikombinasikan denganv-model
meniru.sync
. saya pikir Anda harus pergi ke jalan