Episode ini membedah useEffect untuk side effects, cleanup effect, dan dependency array yang mengontrol kapan efek berjalan. Kalian juga mengenal useMemo dan useCallback untuk optimasi, serta menulis custom hooks agar logika bisa dipakai ulang antar komponen.

Rendering murni tidak cukup untuk aplikasi nyata. Kalian perlu memuat data, mendengarkan event global, mengatur timer, atau mengubah judul dokumen — semuanya adalah side effects. Di React modern, lifecycle dikelola dengan hooks, dan bintang utamanya adalah useEffect.
Episode 6 membedah useEffect secara menyeluruh: kapan dia berjalan, cara membersihkan efek, dan peran dependency array. Kalian juga akan melihat useMemo dan useCallback untuk menghindari pekerjaan dan render yang tidak perlu, lalu belajar menulis custom hooks yang menjadi superpower utama React.
useEffect menerima fungsi yang dijalankan React setelah commit ke DOM. Tanpa dependency array, efek berjalan setelah setiap render:
import { useEffect } from "react"
function App() {
useEffect(() => {
console.log("Komponen dirender")
})
return <h1>Halo</h1>
}Efek di atas berjalan setiap render. Untuk sebagian besar kasus, kalian ingin efek berjalan hanya saat nilai tertentu berubah — itu peran dependency array di bagian berikutnya.
Array kedua pada useEffect berisi nilai yang memicu efek. Tiga bentuk utamanya:
useEffect(() => { /* sekali, saat mount */ }, [])
useEffect(() => { /* saat userId berubah */ }, [userId])
useEffect(() => { /* setiap render */ })useEffect(fn, []) berjalan sekali saat komponen pertama kali dipasang — pengganti componentDidMount. Dengan [userId], efek berjalan saat userId berubah. Tanpa array, berjalan tiap render.
Efek seperti subscription atau timer harus dibersihkan. Fungsi yang dikembalikan dari efek adalah cleanup-nya:
import { useEffect, useState } from "react"
function Jam() {
const [detik, setDetik] = useState(0)
useEffect(() => {
const timer = setInterval(() => setDetik((d) => d + 1), 1000)
return () => clearInterval(timer)
}, [])
return <p>Sudah {detik} detik</p>
}return () => clearInterval(timer) dipanggil React saat komponen dilepas atau sebelum efek dijalankan ulang. Tanpa cleanup, interval terus berjalan dan menyebabkan kebocoran memori.
useMemo menyimpan hasil komputasi dan menghitung ulang hanya saat dependency berubah:
import { useMemo } from "react"
function Daftar({ itemList, filter }) {
const hasil = useMemo(() => {
return itemList.filter((item) => item.nama.includes(filter))
}, [itemList, filter])
return <ul>{hasil.map((item) => <li key={item.id}>{item.nama}</li>)}</ul>
}useMemo(fn, [itemList, filter]) menyimpan hasil filter dan menghitung ulang hanya jika itemList atau filter berubah. Untuk daftar ratusan ribu item, ini menghemat waktu render yang signifikan.
useCallback menyimpan referensi fungsi agar tetap sama antar render, mencegah re-render tidak perlu pada komponen anak:
import { useCallback, useState } from "react"
function Form() {
const [teks, setTeks] = useState("")
const handleChange = useCallback((e) => {
setTeks(e.target.value)
}, [])
return <input value={teks} onChange={handleChange} />
}const handleChange = useCallback(fn, []) membuat handler ini memiliki referensi yang sama di setiap render, berguna saat diteruskan ke komponen anak yang di-memoize. Ingat: gunakan hanya bila perlu — optimasi prematur menambah kompleksitas.
Custom hooks adalah fungsi biasa berawalan use yang memakai hooks lain. Inilah cara terbaik mengekstrak logika yang sama dari banyak komponen:
import { useEffect, useState } from "react"
function useLocalStorage(key, awal) {
const [nilai, setNilai] = useState(() => {
return localStorage.getItem(key) ?? awal
})
useEffect(() => {
localStorage.setItem(key, nilai)
}, [key, nilai])
return [nilai, setNilai]
}
function App() {
const [nama, setNama] = useLocalStorage("nama", "")
return <input value={nama} onChange={(e) => setNama(e.target.value)} />
}useLocalStorage(key, awal) memadukan useState dan useEffect sehingga penyimpanan ke localStorage otomatis. Aturan penting: panggil hooks di level atas fungsi, tanpa kondisi atau loop, dan tanpa mengubah urutan pemanggilan antar render.
Ada dua aturan yang dijaga ESLint (plugin react-hooks): hooks hanya dipanggil dari fungsi React (komponen atau custom hooks), dan urutan pemanggilannya konsisten. Melanggar aturan ini menghasilkan state yang kacau — jadi jalankan lint setelah menulis custom hooks.
npm run lintJika plugin react-hooks terpasang, ESLint otomatis mendeteksi pelanggaran seperti hooks di dalam kondisi. Jaga lint tetap hijau untuk menghindari bug halus.
Episode 6 melengkapi toolkit hooks: useEffect untuk side effects dengan dependency array dan cleanup, useMemo dan useCallback untuk optimasi, serta custom hooks yang membuat logika reusable lintas komponen.
Inti yang harus dibawa pulang:
useEffect berjalan setelah commit; dependency array mengontrol kapan efek berjalan.useMemo menyimpan hasil komputasi; useCallback menyimpan referensi fungsi.use dan mengekstrak logika untuk dipakai ulang.Di episode 7 selanjutnya kita akan membahas conditional rendering & lists — ternary dan logical operators, merender daftar dengan key yang stabil, Fragment, portal, dan error boundaries, plus best practice untuk UI dinamis. Ini saatnya membuat UI kalian benar-benar bercabang dan berulang.