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 denganonClick. Berapa listenerclickyang 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 |
- Nama prop-nya
on+ nama event:onClick,onInput,onKeyDown. Semua handler di JSX Solid diawalion. Solid juga menerima huruf kecil,onclick. - Nilainya fungsi:
() => setCount(c => c + 1). Solid memanggilnya nanti, saat tombolnya diklik. - Dua tombol memakai signal yang sama. Yang beda cuma arah perubahannya. Ini latihan pelajaran ini.
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>
e.targetadalah elemen yang benar-benar diklik atau diketik. Di kotak cari, itu input-nya, jadie.target.valueadalah isinya.- Kalau tulisan tebal Pesan di dalam tombol yang diklik,
e.targetadalah<b>, bukan tombolnya. Console mencetakB BUTTON. e.currentTargetselalu elemen pemilik handler, di sini<button>. Untuk membaca data dari tombolnya, pakaie.currentTarget.
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
- Memanggil fungsinya, bukan memberikannya.
onClick={setCount(count() + 1)}menjalankan setter saat halaman dibuat (hitungannya langsung 1), dan yang jadi handler adalah angka hasilnya. Klik berikutnya berhenti denganTypeError: handler.call is not a function. Bungkus dengan fungsi:onClick={() => setCount(c => c + 1)}. - Tulisan tombolnya gak persis. Latihan ini mencari tombol yang tulisannya persis
-1, lalu mengkliknya.- 1atauKuranggak ketemu. e.targetdi tombol yang punya isi. Kalau tombolnya berisi<b>atau ikon,e.targetbisa elemen di dalamnya. Pakaie.currentTargetuntuk tombolnya.onChangeuntuk mengetik. Gak jalan sebelum kotaknya ditinggalkan.
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.