useEffect Dasar — React

Komponen React punya tugas utama: render UI dari state. Tapi banyak hal yang perlu jalan DI LUAR render — fetch data dari API, set timer, listen ke window…

Tugas utama komponen adalah menghitung tampilan dari state dan props. Tapi kadang komponen perlu menyentuh sesuatu di luar tampilannya sendiri: mengganti judul tab browser, mencatat ke console, menyimpan ke localStorage. Hal-hal begini disebut side effect, dan tempatnya di hook useEffect: kode di dalamnya jalan sesudah React selesai memperbarui halaman. Bayangin teller bank dan papan nomor antrean di dinding. Teller melayani di mejanya, itu render. Papan di dinding ada di luar meja, dan diganti sesudah teller memanggil nomor berikutnya, itu effect. Papannya cuma perlu diganti kalau nomornya berubah, bukan tiap kali teller ganti pulpen. Daftar "ganti kalau ini berubah" itu namanya dependency array.

🧪 Tebakan cepat: sebuah effect mengganti judul tab jadi "Klik: " + count, dengan dependency [count]. Kamu menekan tombol ganti tema, yang mengubah state lain, dan komponennya render ulang. Effect-nya jalan lagi atau gak? Tebak dulu, jawabannya ada di bagian "Dependency array: kapan effect jalan lagi".

Side effect di useEffect

import { useEffect } from "react"

function App() {
  useEffect(() => {
    console.log("Komponen dimuat!")
  }, [])

  return <p>Cek console</p>
}

Judul tab juga di luar tampilan komponen, jadi menggantinya adalah side effect:

function App() {
  useEffect(() => {
    document.title = "Belajar React" // judul tab browser
  }, [])

  return <h1>Lihat judul tab!</h1>
}

Kenapa gak ditulis langsung di badan komponen? Kode di badan komponen jalan tiap render, dan render sebaiknya cuma menghitung tampilan. Di dalam useEffect, kamu yang menentukan kapan side effect jalan.

Dependency array: kapan effect jalan lagi

function Counter() {
  const [count, setCount] = useState(0)
  const [dark, setDark] = useState(false)

  useEffect(() => {
    document.title = `Klik: ${count}`
  }, [count])

  return (
    <div className={dark ? "gelap" : "terang"}>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <button onClick={() => setDark(!dark)}>Ganti tema</button>
    </div>
  )
}

Sesudah tiap render, React membandingkan isi array dengan isinya di render sebelumnya. Ada yang berubah? Effect jalan. Semuanya sama? Effect dilewati.

Kejadian Render ulang? count Effect [count]
Mount ya 0 jalan, judul Klik: 0
Klik +1 ya 1 jalan, karena 0 jadi 1. Judul Klik: 1
Ganti tema ya 1 dilewati, count masih 1
Klik +1 ya 2 jalan, judul Klik: 2

Ganti tema memang membuat render ulang, tapi count gak berubah, jadi effect-nya gak jalan. Itu jawaban tebakannya.

Ditulis Effect jalan
useEffect(fn, []) sekali, saat mount
useEffect(fn, [count]) saat mount, lalu tiap count berubah
useEffect(fn, [a, b]) saat mount, lalu tiap a atau b berubah
useEffect(fn) sesudah setiap render

Tanpa array sama sekali, effect jalan sesudah setiap render. Komponen yang render 3 kali (render pertama ikut dihitung) menjalankan effect-nya 3 kali.

Cleanup, dan kenapa log-nya bisa dobel

Kalau effect me-return sebuah function, function itu disebut cleanup. React memanggilnya sebelum effect yang sama jalan lagi, dan saat komponen dilepas dari halaman (unmount). Di Lab, tiap effect jalan yang baru didahului baris cleanup milik effect sebelumnya. Cara memakainya dibahas di pelajaran useEffect Lanjutan.

Saat development, project React biasanya dibungkus <StrictMode>. Di mode itu React sengaja menjalankan effect saat mount dua kali (effect, cleanup, effect lagi) untuk memeriksa cleanup-mu. Jadi Komponen dimuat! bisa tercetak dua kali di laptopmu. Di build production, cuma sekali. Ini bukan bug di kodemu.

⚠️ Jebakan yang sering ketemu

TL;DR: Side effect (ganti document.title, console.log, localStorage) ditaruh di useEffect(fn, deps), yang jalan sesudah render tampil di halaman. [] artinya sekali saat mount, [count] artinya saat mount dan tiap count berubah, tanpa array artinya sesudah setiap render (render 3 kali, effect 3 kali). Render yang gak mengubah isi array melewati effect-nya. Function yang di-return effect adalah cleanup, jalan sebelum effect berikutnya dan saat unmount. Di development, StrictMode menjalankan effect mount dua kali, di production sekali.

Yang akan kamu pelajari