Component Events — Svelte

Component events memungkinkan child mengirim event ke parent menggunakan createEventDispatcher. Mengirim Event import { createEventDispatcher } from "svelte"…

Component event adalah kabar yang dikirim komponen anak ke induknya, misalnya "menu ini dipesan". Props mengalir turun, dari induk ke anak; event mengalir naik, dari anak ke induk. Bayangin bel di tiap meja Warung Bu Sri. Pembeli menekan bel sambil menyebut "Nasi Goreng". Bunyinya cuma terdengar di ruangan tempat bel itu dipasang. Kasir di ruang depan mendengarnya, tapi Bu Sri di dapur gak, kecuali kasirnya meneruskan pesanan itu. Kalau ruangannya kosong, belnya tetap berbunyi, gak ada yang datang, dan gak ada yang protes.

🧪 Tebakan cepat: App menulis <DaftarMenu on:pesan={tambah} />. Di dalam DaftarMenu, tiap <MenuItem /> ditulis tanpa on:pesan. MenuItem mengirim event pesan saat tombolnya diklik. Apakah tambah di App jalan? Jawabannya ada di bagian "Meneruskan event (forwarding)".

createEventDispatcher: anak mengirim kabar

Ini MenuItem.svelte dari pelajaran Props, sekarang dengan tombol Pesan:

<!-- MenuItem.svelte -->
<script>
  import { createEventDispatcher } from "svelte"

  export let nama
  export let harga

  const dispatch = createEventDispatcher()

  function pesan() {
    dispatch("pesan", { nama, harga })
  }
</script>

<h3>{nama}</h3>
<p>Rp {harga.toLocaleString("id-ID")}</p>
<button on:click={pesan}>Pesan</button>

on:pesan dan event.detail

<!-- App.svelte -->
<script>
  import MenuItem from "./MenuItem.svelte"

  let keranjang = []

  function tambah(event) {
    keranjang = [...keranjang, event.detail.nama]
  }
</script>

<p>Keranjang: {keranjang.length} menu</p>
<MenuItem nama="Nasi Goreng" harga={15000} on:pesan={tambah} />
<MenuItem nama="Es Teh" harga={5000} on:pesan={tambah} />
Kejadian event.detail Tampil
Klik Pesan di Nasi Goreng { nama: "Nasi Goreng", harga: 15000 } Keranjang: 1 menu
Klik Pesan di Es Teh { nama: "Es Teh", harga: 5000 } Keranjang: 2 menu

Event tanpa pendengar

<MenuItem nama="Mie Ayam" harga={12000} /> ditulis tanpa on:pesan. Klik Pesan-nya: dispatch tetap jalan, tapi gak ada yang mendengar. Gak ada error, gak ada warning, bahkan di mode dev, dan keranjangnya gak berubah. Jadi kalau klik tombol gak berefek apa-apa, cek dulu apakah induknya memang mendengarkan nama event yang sama.

Meneruskan event (forwarding)

Sekarang kartunya dibungkus DaftarMenu.svelte, dan App cuma memakai <DaftarMenu on:pesan={tambah} />:

<!-- DaftarMenu.svelte -->
<script>
  import MenuItem from "./MenuItem.svelte"
</script>

<MenuItem nama="Nasi Goreng" harga={15000} on:pesan />
<MenuItem nama="Mie Ayam" harga={12000} on:pesan />
<MenuItem nama="Es Teh" harga={5000} on:pesan />

Latihan: tombol yang mengirim klik

<script>
  import { createEventDispatcher } from "svelte"
  const dispatch = createEventDispatcher()
</script>

<button on:click={() => dispatch("klik", { pesan: "Halo!" })}>
  Klik saya
</button>

Penguji latihannya berperan sebagai induk yang mendengarkan event klik, lalu menekan tombolnya. Karena itu nama event-nya harus persis klik.

Svelte 5: callback props

Di Svelte 5, createEventDispatcher sudah usang (deprecated), walau masih jalan di komponen non-runes. Gantinya callback prop, function yang dikirim induk sebagai prop biasa:

<!-- MenuItem.svelte, Svelte 5 -->
<script>
  let { nama, harga, onpesan } = $props()
</script>

<button onclick={() => onpesan?.({ nama, harga })}>Pesan</button>

Induknya menulis <MenuItem nama="Nasi Goreng" harga={15000} onpesan={tambah} />, dan tambah(menu) langsung menerima { nama, harga }, tanpa event.detail. ?. membuat panggilan itu diam saat induk gak mengirim onpesan. Meneruskan berarti mengoper prop-nya ke bawah: <MenuItem {nama} {harga} {onpesan} />.

⚠️ Jebakan yang sering ketemu

TL;DR: Anak mengirim kabar ke induk dengan const dispatch = createEventDispatcher() (dari "svelte", dipanggil sekali di <script>), lalu dispatch("pesan", { nama, harga }). Induk mendengarkan dengan on:pesan={tambah} dan membaca datanya di event.detail; tanpa argumen kedua, event.detail adalah null. Event tanpa pendengar gak berbuat apa-apa, tanpa error. Event komponen gak bubble, jadi komponen di tengah meneruskannya dengan on:pesan tanpa handler (event forwarding). Di Svelte 5, createEventDispatcher diganti callback prop seperti onpesan. Latihannya: tombol dengan on:click={() => dispatch("klik", { pesan: "Halo!" })}.

Yang akan kamu pelajari