Lifecycle adalah perjalanan hidup sebuah komponen: dia dipasang ke halaman, hidup sebentar, lalu dibongkar. Solid memberi satu fungsi untuk tiap momen itu. onMount(fn) menjalankan fn sekali, sesudah elemen-elemen komponennya ada di halaman. onCleanup(fn) menjalankan fn saat komponennya dibongkar. Bayangin Kak Nadia membuka toko: lampu dinyalakan, jam dinding dipasang baterainya. Waktu tutup, semua yang tadi dinyalakan harus dimatikan lagi. Kalau lupa, lampunya menyala semalaman walau tokonya sudah kosong.
🧪 Tebakan cepat:
App,Header, danJam(yang ada di dalamHeader) masing-masing memanggilonMountdanonCleanupyang mencetak namanya. Halamannya dibuka, lalu ditutup. Urutan apa yang tercetak? Jawabannya ada di bagian "Urutan dengan komponen anak".
onMount: sekali, sesudah elemennya ada di halaman
Bentuk latihan pelajaran ini:
import { createSignal, onMount, onCleanup } from "solid-js"
function App() {
const [pesan, setPesan] = createSignal("Loading...")
onMount(() => {
setPesan("Mounted!")
})
onCleanup(() => {
console.log("Cleaned up")
})
return <p>{pesan()}</p>
}
| Langkah | Yang terjadi | <p> |
|---|---|---|
Badan App jalan |
signal dibuat, fungsi onMount dan onCleanup cuma dicatat |
belum ada |
return |
<p>Loading...</p> dibuat |
ada, belum di halaman |
| Solid memasangnya | elemennya masuk ke halaman | Loading... |
onMount jalan |
setPesan("Mounted!") |
Mounted! |
| Komponen dibongkar | onCleanup jalan, console: Cleaned up |
hilang |
onMount(() => { ... })menerima satu fungsi. Fungsinya dicatat dulu, baru dipanggil sesudah elemennya ada di halaman.Loading...sempat tampil, lalu langsung bergantiMounted!, terlalu cepat untuk terlihat mata.setPesan("Mounted!")mengubah pesannya lewat setter. Latihannya memeriksa setter itu dipanggil di dalamonMountdan<p>akhirnya berbunyiMounted!.onCleanup(() => { ... })juga dicatat di badan komponen, dan baru jalan saat komponennya dibongkar. Di latihan,Appgak pernah dibongkar, jadiCleaned upgak tercetak. Yang diperiksa cumaonCleanupdipanggil dengan fungsi.- Tempat yang pas untuk
onMount: kerja sekali yang butuh elemen di halaman, seperti memberi fokus ke kotak cari atau mengukur lebar elemen.
onMount bukan createEffect
onMount(fn) sama dengan efek yang gak melacak signal apa pun. Dia jalan sekali, lalu selesai:
const [jumlah, setJumlah] = createSignal(0)
createEffect(() => console.log("efek:", jumlah()))
onMount(() => console.log("onMount:", jumlah()))
// tombol +1 Buku memanggil setJumlah(j => j + 1)
Halaman dibuka, lalu +1 Buku diklik dua kali. Diuji di Solid 1.9: efek: 0, onMount: 0, efek: 1, efek: 2. onMount juga membaca jumlah(), tapi bacaan di dalamnya gak dicatat, jadi dia gak jalan lagi. Kerja yang harus mengikuti signal tempatnya di createEffect.
onCleanup: matikan yang kamu nyalakan
Header toko punya jam yang berdetak tiap detik, dan mendengarkan ukuran jendela:
function Jam() {
const [sekarang, setSekarang] = createSignal(new Date())
const id = setInterval(() => setSekarang(new Date()), 1000)
onCleanup(() => clearInterval(id))
return <span class="jam">{sekarang().toLocaleTimeString("id-ID")}</span>
}
function Header() {
const [lebar, setLebar] = createSignal(window.innerWidth)
const ukur = () => setLebar(window.innerWidth)
window.addEventListener("resize", ukur)
onCleanup(() => window.removeEventListener("resize", ukur))
return (
<header>
Toko Buku Kak Nadia · {lebar() < 600 ? "tampilan HP" : "tampilan lebar"} · <Jam />
</header>
)
}
setIntervalmembuat timer yang berdetak terus, dan mengembalikan nomornya,id. Jamnya menampilkan14.05.03, lalu14.05.04, dan seterusnya.- Timer dan listener milik browser, bukan milik komponen. Saat
Jamhilang dari halaman, timernya tetap berdetak, kecuali dihentikan. Itu sebabnyaonCleanup(() => clearInterval(id)). window.addEventListener("resize", ukur)dipasangkan denganremoveEventListenerdengan fungsi yang sama,ukur. Fungsi baru() => ...diremoveEventListenergak melepas apa pun.- Tanpa
onCleanup, menyembunyikan lalu menampilkan jamnya tiga kali meninggalkan tiga timer yang berdetak bersama. Ini yang disebut kebocoran memori (memory leak). onCleanupboleh dipanggil di badan komponen, di dalamonMount, atau di dalamcreateEffect. Di efek, dia jalan sebelum efeknya jalan lagi, seperti di pelajaran effects.
Urutan dengan komponen anak
App merender Header, dan Header merender Jam. Ketiganya mencetak namanya di badan, di onMount, dan di onCleanup. Diuji di Solid 1.9.17, halaman dibuka lalu ditutup:
App: badan
Header: badan
Jam: badan
App: onMount
Header: onMount
Jam: onMount
Jam: onCleanup
Header: onCleanup
App: onCleanup
Badan komponen jalan dari luar ke dalam, karena return milik App yang membuat Header. onMount jalan sesuai urutan dipanggil: App memanggilnya sebelum return, jadi App duluan. Ini kebalikan React, yang menjalankan useEffect anak lebih dulu. onCleanup jalan terbalik, yang terakhir dicatat duluan: dari dalam ke luar, Jam, Header, App. Itu jawaban tebakannya.
Kalau Jam ada di dalam <Show> dan disembunyikan, cuma onCleanup milik Jam yang jalan. Ditampilkan lagi, badan dan onMount milik Jam jalan lagi. App dan Header gak ikut.
⚠️ Jebakan yang sering ketemu
- Lupa
onCleanupuntuk timer atau listener. Timernya tetap jalan setelah komponennya hilang, dan tiap kali komponennya muncul lagi, satu timer baru ditambah. PasangkansetIntervaldenganclearInterval,addEventListenerdenganremoveEventListener. - Mengira
onMountjalan lagi saat signal berubah. Dia jalan sekali dan gak melacak apa pun. Kerja yang mengikuti signal ditulis dengancreateEffect. - Pesannya ditulis sebagai nilai awal.
createSignal("Mounted!")menampilkanMounted!tanpaonMountsama sekali. Latihannya memeriksa ada setter yang dipanggil paling jauh 160 karakter sesudah kataonMount. - Fungsinya gak ditulis langsung. Penilainya mencari
onMount(danonCleanup(yang langsung diikuti(,function, atauasync. TulisonMount(() => { ... }).onMount(setPesan("Mounted!"))malah memanggilsetPesansaat itu juga.
TL;DR: onMount(() => { ... }) jalan sekali, sesudah elemen komponennya ada di halaman, dan gak melacak signal, beda dengan createEffect yang jalan lagi tiap signal-nya berubah. onCleanup(() => { ... }) jalan saat komponennya dibongkar: tempat clearInterval(id) dan removeEventListener. Lupa membereskan berarti timer dan listener menumpuk tiap komponennya muncul lagi. Urutannya: badan dari luar ke dalam, onMount sesuai urutan dipanggil (App, Header, Jam), onCleanup terbalik (Jam, Header, App). Latihannya: onMount(() => { setPesan("Mounted!") }) mengganti Loading... jadi Mounted!, dan onCleanup(() => { console.log("Cleaned up") }).