Event Handling Solid — SolidJS

Solid menggunakan native DOM events dengan syntax JSX. Event Dasar function Counter() { const [count, setCount] = createSignal(0) return ( setCount(c => c +…

Event handler adalah fungsi yang jalan saat pengguna melakukan sesuatu: mengklik tombol, mengetik di kotak. Di JSX Solid, handler ditulis sebagai prop berawalan on pada elemennya: onClick={...}, onInput={...}. Yang menarik ada di belakangnya. Bayangin Toko Buku Kak Nadia punya tombol Pesan di tiap buku. Kak Nadia gak menaruh satu pelayan di tiap tombol. Dia duduk di meja depan, semua klik di toko sampai ke dia, lalu dia melihat tombol mana yang diklik dan menjalankan catatan milik tombol itu. Itu onClick di Solid: satu listener di document untuk semua tombol. Kalau kamu memang mau pelayan di tombolnya sendiri, tulis on:click.

🧪 Tebakan cepat: tiga tombol Pesan, masing-masing dengan onClick. Berapa listener click yang dipasang Solid di halaman, 3 atau 1? Jawabannya ada di bagian "Delegasi: satu listener di document".

onClick: handler sebagai prop

import { createSignal } from "solid-js"

function App() {
  const [count, setCount] = createSignal(0)

  return (
    <div>
      <button onClick={() => setCount(c => c + 1)}>+1</button>
      <button onClick={() => setCount(c => c - 1)}>-1</button>
      <p>Count: {count()}</p>
    </div>
  )
}
Kejadian count() Paragraf
Halaman dibuka 0 Count: 0
Klik +1 1 Count: 1
Dari awal, klik -1 -1 Count: -1

Objek event: e.target dan e.currentTarget

Handler menerima satu argumen, objek event (biasanya dinamai e):

<input onInput={e => setCari(e.target.value)} placeholder="Cari judul" />
<button onClick={e => console.log(e.target.tagName, e.currentTarget.tagName)}>
  <b>Pesan</b> Laskar Pelangi
</button>

Delegasi: satu listener di document

Daftar buku Toko Buku Kak Nadia, dengan tombol Pesan di tiap buku dan kotak cari:

import { createSignal, For } from "solid-js"

const buku = ["Laskar Pelangi", "Bumi Manusia", "Cantik Itu Luka"]

function App() {
  const [dipesan, setDipesan] = createSignal("-")
  const [cari, setCari] = createSignal("")

  function pesan(judul, e) {
    console.log("pesan:", judul, "| target:", e.target.tagName, "| currentTarget:", e.currentTarget.tagName)
    setDipesan(judul)
  }

  return (
    <div>
      <input onInput={e => setCari(e.target.value)} placeholder="Cari judul" />
      <p>Mencari: {cari()}</p>
      <For each={buku}>
        {(judul) => (
          <button onClick={(e) => pesan(judul, e)}>
            <b>Pesan</b> {judul}
          </button>
        )}
      </For>
      <p>Dipesan: {dipesan()}</p>
    </div>
  )
}

Compiler Solid gak memasang listener di tiap tombol. Dia menyimpan handler-nya di elemennya (tombol.$click = handler) lalu memanggil delegateEvents(["click", "input"]) sekali. Hasilnya, diuji di Solid 1.9:

Ditulis Listener yang dipasang
onClick di 3 tombol 1, di document
on:click di 3 tombol 3, satu per tombol
onInput di kotak cari 1, di document
onChange di kotak cari 1, di kotak itu sendiri

Tiga tombol, satu listener. Itu jawaban tebakannya. Saat kamu mengklik Pesan di Bumi Manusia, klik itu naik sampai document, listener Solid berjalan dari elemen yang diklik ke atas, menemukan $click di tombol Bumi Manusia, lalu menjalankannya. Dipesan: Bumi Manusia. Seribu tombol pun tetap satu listener.

Event yang didelegasi cuma yang umum dan menggelembung (bubble): click, input, keydown, pointerdown, dan sejenisnya. onChange, onFocus, onScroll dipasang langsung di elemennya.

on:click: listener langsung di elemen

<button on:click={(e) => pesan(judul, e)}> dikompilasi jadi addEventListener("click", ...) di tombol itu sendiri, gak lewat document. Hasilnya sama di layar, bedanya di cara kerjanya: tiap elemen punya listener-nya sendiri. Pakai ini kalau event-nya harus ditangani di elemen itu juga, misalnya elemen di dalam Shadow DOM, event buatan sendiri dengan nama khusus, atau saat urutan dengan listener native lain penting.

Data untuk handler: bentuk array

<button onClick={[pesan, judul]}>
  <b>Pesan</b> {judul}
</button>

Kalau nilai onClick berupa array [handler, data], Solid memanggil handler-nya dengan data dulu, event kedua: pesan(judul, e), persis seperti (e) => pesan(judul, e) tadi. Bentuk ini gak membuat fungsi baru untuk tiap baris, dan tetap didelegasi.

onInput atau onChange

onInput jalan tiap ketikan. onChange di Solid memakai event change asli browser, yang di kotak teks baru jalan saat kotaknya ditinggalkan atau Enter ditekan. Untuk kotak cari yang mengikuti ketikan, pakai onInput.

⚠️ Jebakan yang sering ketemu

TL;DR: Handler ditulis sebagai prop berawalan on yang berisi fungsi: onClick={() => setCount(c => c - 1)}, onInput={e => setCari(e.target.value)}. Jangan memanggilnya di situ: onClick={setCount(1)} jalan saat render dan klik berikutnya error. onClick didelegasi: berapa pun tombolnya, Solid memasang satu listener di document dan mencari $click dari elemen yang diklik ke atas. on:click memakai addEventListener langsung di elemennya, satu per elemen. e.target elemen yang diklik, e.currentTarget pemilik handler. onClick={[pesan, judul]} memanggil pesan(judul, e). Untuk mengetik, onInput; onChange baru jalan saat kotaknya ditinggalkan.

Yang akan kamu pelajari