Lifecycle Svelte — Svelte

Svelte menyediakan lifecycle functions yang dipanggil pada tahap tertentu. onMount import { onMount } from "svelte" let data = [] onMount(async () => { const…

Lifecycle adalah perjalanan hidup sebuah komponen: dibuat, dipasang ke halaman (mount), diperbarui, lalu dilepas (destroy). Svelte menyediakan function untuk menitipkan kerja di tahap tertentu, terutama onMount dan onDestroy. Bayangin Bu Sri membuka warung. Rolling door dinaikkan dulu sampai warungnya kelihatan, baru dia menyalakan kompor dan menelepon pemasok untuk daftar bahan hari ini. Itu onMount. Waktu tutup, kompornya dimatikan sebelum pintu diturunkan. Itu onDestroy. Kalau lupa, gasnya terus menyala walaupun warungnya sudah tutup.

🧪 Tebakan cepat: MenuHariIni.svelte memulai setInterval jam di onMount, tanpa onDestroy. Pembeli membuka menu, menutupnya, membuka lagi, menutup lagi, lalu membuka sekali lagi. Sekarang ada berapa interval yang jalan: 1 atau 3? Jawabannya ada di bagian "Interval yang lupa dihentikan".

Urutan hidup komponen

Ini yang terjadi saat App.svelte memasang <MenuHariIni />, dari Svelte 4 yang sebenarnya:

Tahap Kapan jalan Di MenuHariIni
<script> sekali, saat komponen dibuat menu = [], jam diisi
render pertama setelah script <p>Memuat menu...</p> masuk halaman
onMount sekali, setelah render pertama interval jam dimulai, ambilMenu() dipanggil
update tiap ada variabel yang berubah jam berganti tiap detik, daftar menu muncul
onDestroy sekali, sebelum komponen dilepas interval dihentikan

onMount: mulai kerja setelah tampil

Ini MenuHariIni.svelte. Server-nya pura-pura: ambilMenu() menjawab setelah 800 ms.

<script>
  import { onMount, onDestroy } from "svelte"

  let menu = []
  let jam = new Date().toLocaleTimeString("id-ID")
  let timer

  function ambilMenu() {
    return new Promise((selesai) => {
      setTimeout(() => selesai(["Nasi Goreng", "Mie Ayam", "Es Teh"]), 800)
    })
  }

  onMount(async () => {
    timer = setInterval(() => {
      jam = new Date().toLocaleTimeString("id-ID")
    }, 1000)
    menu = await ambilMenu()
  })

  onDestroy(() => {
    clearInterval(timer)
  })
</script>

<p>Jam {jam}</p>
{#if menu.length === 0}
  <p>Memuat menu...</p>
{:else}
  <ul>
    {#each menu as nama}
      <li>{nama}</li>
    {/each}
  </ul>
{/if}
Waktu Yang tampil
0 ms, render pertama Jam 10.15.03, Memuat menu...
800 ms Jam 10.15.03, daftar Nasi Goreng, Mie Ayam, Es Teh
1.000 ms Jam 10.15.04, daftar yang sama

onDestroy: bereskan sebelum pergi

onDestroy(callback) jalan sekali, tepat sebelum komponen dilepas, misalnya saat {#if tampil} di App jadi false. Di sini tempat menghentikan apa pun yang kamu mulai: clearInterval, removeEventListener, atau berhenti berlangganan store.

onMount juga boleh mengembalikan function, dan Svelte menjalankannya sebagai cleanup saat komponen dilepas: onMount(() => { const t = setInterval(...); return () => clearInterval(t) }). Tapi itu cuma berlaku untuk callback biasa. Callback async selalu mengembalikan Promise, bukan function, jadi cleanup-nya diabaikan. Karena onMount di MenuHariIni async, interval-nya dihentikan di onDestroy.

Interval yang lupa dihentikan

Tanpa onDestroy, komponennya hilang dari halaman tapi interval-nya tetap jalan. Tiap buka-tutup meninggalkan satu:

Kejadian Komponen di halaman Interval yang jalan
Buka MenuHariIni #1 1
Tutup (gak ada) 1, tanpa pemilik
Buka MenuHariIni #2 2
Tutup (gak ada) 2, tanpa pemilik
Buka MenuHariIni #3 3

Jadi jawabannya 3 interval. Itu jawaban tebakannya. Dua di antaranya terus mengubah variabel milik komponen yang sudah gak ada. Ini disebut memory leak: kerja dan memori yang gak pernah dilepas. Dengan onDestroy(() => clearInterval(timer)), angkanya selalu 1 saat menu terbuka, dan 0 saat tertutup.

Latihan: pesan setelah mount

Kode awalnya punya let pesan = "Loading..." dan <p>{pesan}</p>. Jawabannya:

<script>
  import { onMount } from "svelte"

  let pesan = "Loading..."

  onMount(() => {
    pesan = "Komponen sudah dimount!"
  })
</script>

<p>{pesan}</p>

Render pertama menampilkan Loading..., lalu onMount mengganti pesan, dan paragrafnya jadi Komponen sudah dimount!.

📌 beforeUpdate, afterUpdate, dan tick

Svelte 4 punya dua lagi. beforeUpdate jalan sebelum DOM diperbarui (termasuk sekali sebelum render pertama), dan afterUpdate jalan setelahnya. Urutan nyatanya saat komponen dibuat: <script>, beforeUpdate, onMount, lalu afterUpdate.

tick() adalah Promise yang selesai setelah pembaruan DOM berikutnya. Setelah porsi += 1, heading Porsi: {porsi} masih membaca Porsi: 1; setelah await tick(), baru Porsi: 2. Pakai tick kalau kodemu perlu membaca DOM yang baru.

Svelte 5

onMount, onDestroy, dan tick masih dipakai dengan cara yang sama di Svelte 5. beforeUpdate dan afterUpdate gak bisa dipakai di komponen runes: compiler menolak dengan beforeUpdate cannot be used in runes mode. Gantinya $effect.pre (sebelum DOM diperbarui) dan $effect (setelahnya). $effect juga bisa menggantikan pasangan onMount dan onDestroy untuk interval:

<script>
  let jam = $state(new Date().toLocaleTimeString("id-ID"))

  $effect(() => {
    const timer = setInterval(() => {
      jam = new Date().toLocaleTimeString("id-ID")
    }, 1000)
    return () => clearInterval(timer)
  })
</script>

⚠️ Jebakan yang sering ketemu

TL;DR: Komponen hidup dalam urutan: <script> jalan, render pertama, onMount, update tiap ada perubahan, lalu onDestroy sebelum dilepas. Semua function lifecycle diimpor dari "svelte". onMount jalan sekali setelah komponen tampil dan cuma di browser, jadi tempat mengambil data (menu = await ambilMenu()) dan memulai interval. onDestroy tempat bersih-bersih, misalnya clearInterval(timer); tanpa itu, tiap buka-tutup meninggalkan interval yang terus jalan. onMount boleh mengembalikan cleanup, tapi gak kalau callback-nya async. tick() menunggu DOM selesai diperbarui. Di Svelte 5, beforeUpdate dan afterUpdate diganti $effect.pre dan $effect. Latihannya: onMount(() => { pesan = "Komponen sudah dimount!" }), sehingga <p> berubah dari Loading... jadi Komponen sudah dimount!.

Yang akan kamu pelajari