Suspense & Lazy — React

Pas user buka aplikasi pertama kali, browser download SEMUA JavaScript bundle — kalau gede (1-2MB), waktu loading awal lambat (terutama di koneksi lemah)…

Tanpa pengaturan apa-apa, seluruh JavaScript app dikirim dalam satu file besar (bundle), dan halaman baru tampil setelah file itu selesai diunduh. lazy memisahkan satu komponen ke file sendiri (chunk) yang baru diunduh waktu komponen itu pertama kali dirender, dan Suspense menampilkan tampilan sementara (fallback) selama chunk-nya masih di jalan. Bayangin warung makan. Nasi dan lauk utama sudah siap di etalase, jadi pembeli langsung dilayani. Es campur baru dibuat waktu ada yang pesan, dan selama dibuat pelayannya bilang "sebentar ya". Begitu bahan es campur sudah keluar dari kulkas, pesanan berikutnya bisa langsung jadi.

🧪 Tebakan cepat: HeavyChart sudah pernah dimuat sekali dengan lazy, lalu disembunyikan, lalu ditampilkan lagi. Apakah fallback Sedang memuat... muncul lagi? Tebak dulu, jawabannya ada di bagian "Kedua kalinya langsung tampil".

Satu bundle besar, atau dipecah

Misalnya app dashboard-mu berukuran 300 KB, dan 180 KB di antaranya komponen grafik HeavyChart yang baru dipakai setelah tombol diklik.

Cara Diunduh sebelum halaman tampil Diunduh nanti
Satu bundle 300 KB gak ada
HeavyChart di-lazy 120 KB 180 KB, waktu grafiknya pertama kali dirender

Di koneksi sekitar 200 KB per detik, 300 KB butuh kira-kira 1,5 detik, sedangkan 120 KB cuma 0,6 detik. Pengguna yang gak pernah membuka grafik gak pernah mengunduh 180 KB itu sama sekali. Teknik memecah bundle seperti ini disebut code splitting.

lazy dan Suspense

import { lazy, Suspense, useState } from "react"

const HeavyChart = lazy(() => import("./HeavyChart"))

function App() {
  const [tampil, setTampil] = useState(false)
  return (
    <div>
      <button onClick={() => setTampil(true)}>Muat Komponen</button>
      {tampil && (
        <Suspense fallback={<p id="fallback">Sedang memuat...</p>}>
          <HeavyChart />
        </Suspense>
      )}
    </div>
  )
}
Waktu Yang terjadi Yang tampil
0 detik Tombol diklik, HeavyChart dirender, chunk mulai diunduh Sedang memuat...
0,9 detik Chunk 180 KB selesai Komponen Berhasil Dimuat! dan grafiknya

Kedua kalinya langsung tampil

lazy mengingat hasil import-nya. Setelah chunk pertama kali selesai, HeavyChart yang disembunyikan lalu ditampilkan lagi langsung muncul, tanpa fallback dan tanpa unduhan baru. Itu jawaban tebakannya: fallback-nya gak muncul lagi. Browser juga menyimpan file chunk-nya di cache, jadi kunjungan berikutnya pun lebih cepat.

Mensimulasikan dengan state

Editor latihan gak punya file lain untuk di-import. Di latihan pertama, import-nya ditiru dengan promise yang selesai 300 ms kemudian dengan { default: Grafik }, jadi lazy dan Suspense sungguhan menampilkan fallback-nya. Di latihan kedua, kamu meniru tiga keadaannya dengan state biasa: belum dimuat, sedang memuat, sudah dimuat.

function App() {
  const [loaded, setLoaded] = useState(false)
  const [loading, setLoading] = useState(false)

  const handleLoad = () => {
    setLoading(true)
    setLoaded(true)
    setLoading(false)
  }

  return (
    <div>
      <button id="load" onClick={handleLoad}>Muat Komponen</button>
      {!loaded && !loading && <p id="placeholder">Klik tombol untuk memuat</p>}
      {loading && <p id="fallback">Sedang memuat...</p>}
      {loaded && <div id="lazy-content">Komponen Berhasil Dimuat!</div>}
    </div>
  )
}

⚠️ Jebakan yang sering ketemu

TL;DR: lazy(() => import("./HeavyChart")) memisahkan komponen ke chunk sendiri yang diunduh waktu pertama kali dirender, dan <Suspense fallback={...}> menampilkan fallback selama chunk-nya di jalan. Hasilnya bundle awal lebih kecil dan halaman lebih cepat tampil: 300 KB jadi 120 KB di contoh tadi. lazy ditulis di luar komponen dan butuh export default. Setelah dimuat sekali, komponennya langsung tampil tanpa fallback. Di latihan pertama, import-nya ditiru dengan promise, dan di latihan kedua, tiga keadaannya (placeholder, #fallback, #lazy-content) ditiru dengan state.

Yang akan kamu pelajari