useEffect Adalah: Cara Pakai Hook useEffect di React (Panduan Pemula + Dependency Array)
useEffect adalah hook React untuk menjalankan side effect. Pahami dependency array (tanpa array vs [] vs [deps]), cleanup, dan cara pakainya lewat contoh interaktif.
Pembuat Hyper Sheets & BelajarWeb.dev
useEffect adalah hook bawaan React yang dipakai untuk menjalankan side effect, kode yang berinteraksi dengan dunia di luar React, seperti mengambil data dari API, mengubah judul tab browser, memasang event listener, atau menyimpan data ke localStorage. Kalau useState bertugas menyimpan data yang berubah, useEffect bertugas menjalankan “efek samping” setiap kali komponen dirender atau saat data tertentu berubah. Hook ini adalah salah satu dari dua hook paling fundamental di React, dan sekaligus yang paling sering bikin pemula bingung.
Kabar baiknya, 90% kebingungan soal useEffect bersumber dari satu hal yang sama: dependency array, argumen kedua yang menentukan kapan effect dijalankan ulang. Begitu bagian itu klik di kepalamu, sisanya jadi jauh lebih masuk akal. Di panduan ini kamu akan memahami useEffect benar-benar dari nol, mulai dari apa itu side effect, sintaks dasarnya, perbedaan antara tanpa array vs [] vs [deps] (lengkap dengan demo interaktif yang bisa kamu klik-klik sendiri), sampai fungsi cleanup dan kesalahan umum yang bikin aplikasi nge-lag.
Apa Itu Side Effect di React?
Side effect adalah segala aktivitas yang menyentuh dunia di luar proses render komponen, misalnya memanggil API, membaca/menulis ke localStorage, mengganti document.title, memasang setInterval, atau menambah event listener ke window. React punya prinsip: fungsi komponen idealnya “murni”, artinya ia hanya menerima props dan state, lalu mengembalikan JSX, tanpa efek samping ke luar.
Masalahnya, aplikasi nyata mustahil tanpa side effect. Kamu pasti butuh mengambil data dari server, menyimpan preferensi pengguna, atau menyinkronkan sesuatu dengan browser. Nah, useEffect adalah tempat resmi yang disediakan React untuk menaruh kode semacam itu, supaya ia berjalan pada waktu yang tepat (setelah render selesai), bukan di tengah-tengah proses render yang bisa merusak tampilan.
Sintaks Dasar useEffect
useEffect menerima dua argumen: sebuah fungsi berisi kode effect, dan sebuah dependency array opsional. Bentuk paling dasarnya seperti ini:
import { useState, useEffect } from 'react'
function JudulHalaman() {
const [hitung, setHitung] = useState(0)
useEffect(() => {
// ini kode side effect-nya:
document.title = `Kamu klik ${hitung} kali`
}, [hitung]) // ← dependency array
return (
<button onClick={() => setHitung(hitung + 1)}>
Klik saya ({hitung})
</button>
)
}
Perhatikan strukturnya:
- Argumen pertama adalah fungsi (
() => { ... }) yang berisi kode effect. React akan menjalankannya setelah komponen selesai dirender ke layar. - Argumen kedua adalah dependency array (
[hitung]). Ini “daftar pengawasan”, React hanya menjalankan ulang effect kalau salah satu nilai di dalam array ini berubah dibanding render sebelumnya.
Di contoh di atas, setiap kali hitung bertambah, judul tab browser ikut berubah. Effect ini “bereaksi” terhadap perubahan hitung. Kamu harus meng-import useEffect dari react sama seperti useState.
Dependency Array: Bagian Paling Penting
Dependency array menentukan kapan effect dijalankan ulang, dan ada tiga bentuk yang wajib kamu bedakan: tanpa array (setiap render), array kosong [] (sekali saja), dan array berisi nilai [deps] (saat nilai itu berubah). Ini adalah inti dari useEffect. Salah memilih bentuk di sini adalah sumber bug paling umum di React, mulai dari data yang tidak ter-update sampai infinite loop yang membekukan browser.
Mari bedah ketiganya satu per satu:
// 1. TANPA dependency array
// → effect jalan setiap kali komponen render (nyaris tidak pernah kamu mau)
useEffect(() => {
console.log('Jalan di SETIAP render')
})
// 2. Array KOSONG []
// → effect jalan SEKALI saja, setelah mount pertama
useEffect(() => {
console.log('Jalan sekali saat komponen muncul')
}, [])
// 3. Array BERISI [nilai]
// → effect jalan saat mount, DAN setiap kali `userId` berubah
useEffect(() => {
console.log('Jalan saat userId berubah')
}, [userId])
Cara paling cepat memahami perbedaan ini adalah dengan melihatnya bergerak. Di playground di bawah, pilih bentuk dependency array, lalu klik tombol-tombolnya dan perhatikan log effect: kapan effect dijalankan, kapan cleanup dipanggil, dan kapan effect justru dilewati.
Coba Sendiri
● ter-mountDependency array
useEffect(() => {
document.title = 'Klik: ' + hitung
return () => {
// cleanup
}
}, [hitung])Log effect
Coba perhatikan pola yang muncul saat kamu bermain di atas:
- Tanpa array, effect jalan lagi setiap kali ada render, termasuk saat kamu klik “Re-render tanpa ubah hitung”. Ini boros dan berisiko infinite loop.
- Array kosong
[], apa pun yang kamu klik, effect tidak pernah jalan lagi setelah mount pertama. Cocok untuk setup yang cuma perlu sekali, misalnya fetch data awal. [hitung], effect hanya jalan ulang saathitungbenar-benar berubah. Klik “Re-render tanpa ubah hitung” dan effect akan dilewati, karenahitungtidak berubah.
Aturan praktisnya: masukkan ke dependency array semua nilai reaktif (props dan state) yang kamu pakai di dalam effect. Kalau effect membaca userId dan token, keduanya harus ada di array: [userId, token]. React bahkan menyediakan aturan ESLint (react-hooks/exhaustive-deps) yang otomatis mengingatkanmu kalau ada dependency yang lupa dimasukkan.
Fungsi Cleanup: Membereskan Sisa Effect
Fungsi cleanup adalah fungsi yang kamu return dari dalam useEffect, dan React menjalankannya untuk membereskan effect sebelumnya, sebelum effect jalan lagi, atau saat komponen dilepas dari layar (unmount). Cleanup wajib dipakai setiap kali effect-mu “memasang” sesuatu yang perlu dilepas kembali: timer, event listener, atau koneksi.
Contoh klasik dengan setInterval:
useEffect(() => {
const timer = setInterval(() => {
console.log('tick setiap detik')
}, 1000)
// fungsi cleanup:
return () => {
clearInterval(timer) // hentikan timer saat komponen hilang
}
}, [])
Tanpa baris clearInterval di cleanup, setiap kali komponen muncul-hilang-muncul lagi, timer baru akan terus menumpuk tanpa yang lama pernah dihentikan. Ini yang disebut memory leak, aplikasi makin lama makin berat karena “sampah” yang tidak dibersihkan.
Contoh lain, memasang event listener ke window:
useEffect(() => {
function handleResize() {
console.log('lebar layar:', window.innerWidth)
}
window.addEventListener('resize', handleResize)
// cleanup: lepas listener supaya tidak dobel
return () => {
window.removeEventListener('resize', handleResize)
}
}, [])
Di playground tadi, tombol “Unmount komponen” mensimulasikan momen cleanup ini: saat komponen dilepas, fungsi cleanup terakhir dipanggil sebelum komponen benar-benar hilang. Urutannya selalu: cleanup effect lama → baru effect baru dijalankan.
Contoh Nyata: Fetch Data dengan useEffect
Salah satu kegunaan useEffect paling umum adalah mengambil data dari API saat komponen pertama kali muncul. Polanya menggabungkan useState (untuk menyimpan hasil) dan useEffect (untuk memicu fetch):
import { useState, useEffect } from 'react'
function ProfilUser({ userId }) {
const [user, setUser] = useState(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
setLoading(true)
fetch(`https://api.contoh.com/users/${userId}`)
.then((res) => res.json())
.then((data) => {
setUser(data)
setLoading(false)
})
}, [userId]) // fetch ulang tiap kali userId berubah
if (loading) return <p>Memuat...</p>
return <h1>{user.name}</h1>
}
Karena userId ada di dependency array, komponen otomatis mengambil data user baru setiap kali prop userId berubah, misalnya saat pengguna berpindah dari profil satu ke profil lain. Kalau kamu menulis [] alih-alih [userId], data hanya diambil sekali dan tidak akan pernah ter-update meski userId berganti. Inilah kenapa memilih isi dependency array itu krusial.
Untuk mendalami useEffect dengan latihan interaktif yang bisa kamu ketik dan jalankan langsung di browser, lanjutkan ke materi dasar useEffect di learnhypersheets, kamu akan menulis kode effect sungguhan dan melihat hasilnya secara real-time.
Kesalahan Umum Pemula dengan useEffect
Sebelum lanjut, kenali tiga jebakan yang paling sering menimpa pemula:
- Lupa dependency array padahal effect meng-update state, menyebabkan infinite loop. Selalu tanya: “kapan sebenarnya effect ini perlu jalan ulang?”
- Menaruh terlalu banyak logika di satu effect, lebih baik pisah menjadi beberapa
useEffectyang masing-masing punya satu tanggung jawab, dengan dependency array-nya sendiri. - Lupa cleanup pada timer/listener, menyebabkan memory leak dan bug aneh seperti event yang terpanggil berkali-kali.
Kamu menulis useEffect(() => { ... }, []) dengan dependency array kosong. Kapan effect ini dijalankan?
FAQ Seputar useEffect
Apa bedanya useEffect dan useState?
useState untuk menyimpan data yang bisa berubah di dalam komponen (misalnya isi input, jumlah klik). useEffect untuk menjalankan side effect sebagai reaksi terhadap perubahan (misalnya fetch data saat id berubah, menyimpan ke localStorage saat data berubah). Keduanya sering dipakai bersama: useState menyimpan hasil fetch, useEffect yang memicu fetch-nya.
Kapan sebaiknya pakai dependency array kosong []?
Pakai [] saat kamu ingin effect berjalan tepat sekali setelah komponen muncul dan tidak perlu diulang, misalnya mengambil data awal, memasang event listener global sekali, atau menginisialisasi library pihak ketiga. Ingat, kalau effect membaca props atau state, kamu biasanya tidak boleh memaksakan []; masukkan nilai yang dibaca ke dalam array.
Kenapa useEffect saya menyebabkan infinite loop?
Penyebab paling umum: effect meng-update sebuah state, tapi state itu (atau tidak adanya dependency array sama sekali) membuat effect terpicu lagi tanpa henti. Perbaikannya adalah menulis dependency array yang tepat, atau memindahkan update state ke event handler kalau memang bukan side effect. Cek juga apakah kamu memasukkan object/array baru ke dependency array yang selalu dianggap “berubah” tiap render.
Apakah useEffect wajib punya fungsi cleanup?
Tidak wajib. Cleanup hanya diperlukan kalau effect-mu memasang sesuatu yang perlu dilepas: timer (setInterval/setTimeout), event listener, atau koneksi/subscription. Kalau effect-mu hanya mengubah document.title atau melakukan console.log, kamu tidak perlu menuliskan return.
Bolehkah pakai lebih dari satu useEffect dalam satu komponen?
Boleh, dan justru sering dianjurkan. Pisahkan effect berdasarkan tanggung jawabnya, satu useEffect untuk sinkronisasi judul halaman, satu lagi untuk fetch data, masing-masing dengan dependency array-nya sendiri. Kode jadi lebih mudah dibaca dan di-debug dibanding menumpuk semuanya di satu effect raksasa.
Apakah useEffect masih relevan, atau sudah digantikan?
useEffect masih relevan dan tetap ada di React modern. Namun untuk fetch data yang serius, banyak tim kini memakai library seperti TanStack Query yang menangani caching dan sinkronisasi secara otomatis, sehingga kamu jarang menulis useEffect + fetch manual. Meski begitu, memahami useEffect tetap fondasi wajib, library-library itu pun dibangun di atas konsep yang sama. Untuk mendalaminya sambil praktik, coba materi useEffect interaktif.
Sampai di sini, kamu sudah memahami inti useEffect: ia adalah tempat menjalankan side effect, dan dependency array-lah yang mengatur kapan effect itu jalan. Kuasai tiga bentuk dependency array dan kebiasaan menulis cleanup, maka mayoritas bug useEffect tidak akan pernah menyentuhmu. Buka lagi playground di atas kapan pun kamu ragu, dan teruslah membangun!