Memahami Props dan Emit di Vue.js: Komunikasi Antar Komponen

Vue.js adalah framework JavaScript progresif yang terkenal karena kemudahan dalam membangun antarmuka pengguna (UI) berbasis komponen. Dalam pengembangan aplikasi nyata, sangat jarang kita hanya menggunakan satu komponen saja. Biasanya, aplikasi terdiri dari banyak komponen kecil yang saling berinteraksi satu sama lain.

Nah, agar semua komponen ini bisa bekerja sama dengan baik, kita butuh mekanisme komunikasi yang jelas dan efisien. Dua cara paling umum yang digunakan di Vue adalah props dan emit. Props digunakan untuk mengalirkan data dari parent ke child, sedangkan emit digunakan oleh child untuk mengirimkan event kembali ke parent.

Artikel ini akan mengulas lebih dalam tentang kedua konsep ini, lengkap dengan contoh kasus nyata dan praktik terbaik, agar kamu tidak hanya tahu cara pakainya, tapi juga paham kapan dan kenapa harus digunakan.

1. Apa Itu Props di Vue.js?

Props (singkatan dari properties) adalah mekanisme di Vue untuk mengirim data dari komponen induk (parent) ke komponen anak (child). Dalam struktur komponen Vue, props bersifat read-only — child bisa mengaksesnya, tapi tidak boleh mengubah nilainya secara langsung. Ini sesuai dengan prinsip data flow satu arah di Vue.js.

Contoh Dasar Props
<!-- ParentComponent.vue -->
<template>
<UserCard :username="'Budi'" />
</template>

<script setup>
import UserCard from './UserCard.vue';
</script>
vueCopyEdit<!-- UserCard.vue -->
<template>
<div class="card">
<p>Halo, {{ username }}!</p>
</div>
</template>

<script setup>
defineProps({
username: String
});
</script>

Di sini, komponen UserCard menerima props bernama username. Parent mengoper nilai 'Budi' yang kemudian ditampilkan oleh child.

Props dengan Validasi dan Default Value

Vue juga memungkinkan kamu untuk memvalidasi props, memberi default value, dan bahkan menentukan apakah props tersebut wajib diisi:

<script setup>
defineProps({
username: {
type: String,
required: true,
default: 'Guest'
}
});
</script>

2. Apa Itu Emit di Vue.js?

Kebalikannya dari props, emit digunakan oleh child untuk mengirimkan event ke parent. Konsep ini sangat penting saat child melakukan sesuatu yang parent perlu tahu — misalnya ketika sebuah tombol diklik atau form diisi.

Contoh Dasar Emit
<!-- ChildButton.vue -->
<template>
<button @click="handleClick">Klik Saya</button>
</template>

<script setup>
const emit = defineEmits(['clicked']);

function handleClick() {
emit('clicked');
}
</script>
<!-- ParentComponent.vue -->
<template>
<ChildButton @clicked="handleClick" />
</template>

<script setup>
import ChildButton from './ChildButton.vue';

function handleClick() {
alert('Tombol di child diklik!');
}
</script>

Saat tombol di dalam ChildButton diklik, event clicked dipancarkan ke parent, yang kemudian mengeksekusi handleClick.

Emit dengan Payload

Kamu juga bisa mengirim data melalui emit:

emit('itemSelected', itemId);

Parent tinggal menangkap event tersebut:

<ChildComponent @itemSelected="handleSelect" />

function handleSelect(id) {
console.log('Item dengan ID', id, 'dipilih');
}

3. Studi Kasus: Komponen Form Input Kustom

Salah satu penerapan props dan emit yang sering digunakan adalah pada input form dengan v-model. Vue memungkinkan kita membuat komponen input kustom yang berperilaku seperti input biasa.

FormInput.vue
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>

<script setup>
defineProps(['modelValue']);
</script>
ParentComponent.vue
<template>
<FormInput v-model="nama" />
<p>Nama yang diinput: {{ nama }}</p>
</template>

<script setup>
import { ref } from 'vue';
import FormInput from './FormInput.vue';

const nama = ref('');
</script>

Konvensi update:modelValue ini adalah bagian dari v-model binding, yang memungkinkan parent dan child saling sinkron saat nilai berubah.


4. Tips dan Best Practice

  1. Gunakan nama props yang deskriptif
    Hindari nama pendek seperti val atau x. Gunakan username, userAge, dll. agar lebih mudah dipahami.
  2. Jangan ubah props langsung di child
    Jika butuh memodifikasi nilai props, buat salinannya ke ref atau reactive. vueCopyEditconst props = defineProps(['title']); const localTitle = ref(props.title); // aman diubah
  3. Gunakan emit dengan nama event yang jelas
    Hindari nama umum seperti change, gunakan inputChanged, formSubmitted, dll.
  4. Gunakan defineEmits dan defineProps untuk tipe yang eksplisit
    Ini membantu dokumentasi otomatis dan validasi saat development.
  5. Komunikasi sebaiknya tetap searah
    Jika komunikasi antar komponen terlalu rumit, pertimbangkan menggunakan event bus, store (seperti Pinia atau Vuex), atau mengatur ulang struktur komponennya.

Props dan emit adalah dua konsep fundamental yang harus dipahami oleh semua developer Vue. Mereka memungkinkan kita membangun komponen yang reusable, fleksibel, dan mudah diatur. Props memungkinkan parent mengalirkan data ke child, sementara emit memungkinkan child memberi tahu parent tentang suatu kejadian.

Dengan menguasai keduanya, kamu bisa membangun UI yang rapi, modular, dan lebih mudah di-maintain. Dan yang lebih penting lagi, kamu akan lebih nyaman saat membuat komponen kompleks karena tahu persis bagaimana cara menghubungkannya.

Mulailah dengan eksperimen kecil. Ubah teks dengan props, tangkap klik dengan emit, dan terus eksplorasi. Karena seperti halnya membangun UI yang bagus, komunikasi antar komponen juga butuh fondasi yang kuat.