Actions Svelte — Svelte

Actions (use:) adalah fungsi yang dipanggil saat elemen ditambahkan ke DOM — seperti custom directive. Membuat Action export function clickOutside(node) {…

Action adalah function biasa yang Svelte panggil saat sebuah elemen masuk ke DOM. Kamu menempelkannya ke elemen dengan use:namaAction, dan function itu menerima elemennya langsung, jadi dia bisa memberi fokus, memasang atribut, atau mendengarkan klik. Bayangin penjepit bon di Warung Bu Sri. Penjepit yang sama bisa dipasang ke piring mana saja: saat dipasang, bon dijepit; kalau pesanan berubah, kertas bonnya diganti; saat piring diangkat, penjepitnya dilepas supaya gak tercecer di meja. Piring itu elemennya, bon itu parameternya, dan tiga momen itu adalah pasang, update, dan destroy.

🧪 Tebakan cepat: action klikDiLuar menutup dropdown keranjang saat pembeli mengklik di luarnya, tapi lupa diberi destroy. Dropdown dibuka, lalu ditutup dengan klik di luar. Dibuka lagi, lalu pembeli mengklik baris Nasi Goreng di dalamnya. Dropdown-nya tetap terbuka, atau malah tertutup? Jawabannya ada di bagian "destroy: lepas yang kamu pasang".

Action pertama: autofocus

<script>
  function autofocus(node) {
    node.focus()
  }
</script>

<input use:autofocus placeholder="Cari menu..." />

Latihan pertama persis ini: kode awalnya sudah punya function autofocus, kamu tinggal memasang use:autofocus di <input>.

Parameter dan update: tooltip total

Action boleh menerima satu nilai: tulis use:tooltip={nilai}, dan nilai itu jadi argumen kedua. Kalau action mengembalikan objek berisi update dan destroy, Svelte memanggil update tiap nilainya berubah, dan destroy saat elemennya dilepas.

<script>
  let porsiEsTeh = 3

  $: total = 2 * 15000 + 12000 + porsiEsTeh * 5000

  function tooltip(node, teks) {
    node.setAttribute("title", teks)

    return {
      update(teksBaru) {
        node.setAttribute("title", teksBaru)
      },
      destroy() {
        node.removeAttribute("title")
      },
    }
  }
</script>

<button use:tooltip={`Total Rp ${total.toLocaleString("id-ID")}`}>Keranjang (3)</button>
<button on:click={() => (porsiEsTeh += 1)}>+1 Es Teh</button>

Keranjangnya sama dengan pelajaran Animations: Nasi Goreng x2, Mie Ayam x1, Es Teh x3. Ini yang Svelte 4 panggil:

Kejadian Yang dipanggil title tombol Keranjang
tombol masuk ke DOM tooltip(button, "Total Rp 57.000") Total Rp 57.000
klik +1 Es Teh update("Total Rp 62.000") Total Rp 62.000
variabel lain berubah gak ada tetap
tombol dilepas destroy() atribut dihapus

Latihan kedua membuat action ini sendiri: tooltip(node, text) dengan setAttribute('title', text), dipasang dengan use:tooltip={'Ini tooltip'} di <button>.

klikDiLuar: menutup dropdown keranjang

<script>
  let buka = false

  function klikDiLuar(node, tutup) {
    function cek(event) {
      if (!node.contains(event.target)) tutup()
    }
    // true: dengarkan di fase capture (penjelasannya di bawah)
    document.addEventListener("click", cek, true)

    return {
      update(tutupBaru) {
        tutup = tutupBaru
      },
      destroy() {
        document.removeEventListener("click", cek, true)
      },
    }
  }
</script>

<button on:click={() => (buka = true)}>Keranjang (3)</button>

{#if buka}
  <div class="dropdown" use:klikDiLuar={() => (buka = false)}>
    <p>Nasi Goreng x2</p>
    <p>Mie Ayam x1</p>
    <p>Es Teh x3</p>
  </div>
{/if}

destroy: lepas yang kamu pasang

Sekarang destroy dihapus dari klikDiLuar. Ini yang terjadi, dicoba di browser dengan Svelte 4:

Kejadian Dengan destroy Tanpa destroy
buka 1 listener 1 listener
klik di luar, dropdown tertutup 0 listener 1 listener, memegang dropdown lama
buka lagi 1 listener 2 listener
klik Nasi Goreng di dalam dropdown tetap terbuka tertutup

Listener pertama gak pernah dilepas, dan dia masih memegang node dropdown pertama, yang sudah dibuang dari halaman. Dropdown yang sudah dibuang gak berisi apa pun yang ada di halaman, jadi node.contains(event.target) selalu false, dan listener lama itu menganggap tiap klik sebagai klik di luar. Klik di Nasi Goreng pun memanggil tutup(). Jadi dropdown-nya tertutup. Itu jawaban tebakannya.

Masalahnya juga menumpuk: setelah tiga kali buka-tutup, tiap klik di mana pun menjalankan tiga cek sekaligus. Ini memory leak yang sama dengan interval yang lupa dihentikan di pelajaran Lifecycle. Aturannya: apa pun yang action pasang di luar elemennya sendiri (listener di document atau window, interval, observer) harus dilepas di destroy.

Svelte 5

use: jalan sama persis di Svelte 5, juga di komponen yang memakai runes. Svelte 5.29 menambah cara yang lebih baru, {@attach ...}: function-nya menerima elemen, mengembalikan function pembersih, dan dijalankan ulang otomatis saat state yang dibacanya berubah, jadi gak perlu update. Latihannya di-compile dengan Svelte 4, jadi tulis use:.

⚠️ Jebakan yang sering ketemu

TL;DR: Action adalah function namaAction(node, parameter) yang dipasang dengan use:namaAction={parameter} dan dipanggil sekali saat elemennya masuk ke DOM, jadi aman memakai DOM di dalamnya: node.focus(), node.setAttribute("title", teks), atau listener klik. Action boleh mengembalikan { update, destroy }: update(nilaiBaru) jalan saat parameternya berubah, destroy() jalan saat elemennya dilepas. Semua yang dipasang di luar elemennya harus dilepas di destroy; tanpa itu, listener klikDiLuar menumpuk dan menutup dropdown yang baru dibuka. Listener di document untuk klik di luar pakai fase capture (true), supaya klik pembukanya gak langsung menutupnya. Action cuma untuk elemen HTML, bukan komponen. Di Svelte 5, use: tetap jalan, dan {@attach} adalah alternatif yang lebih baru. Latihannya: <input use:autofocus />, lalu <button use:tooltip={'Ini tooltip'}>Hover saya</button>.

Yang akan kamu pelajari