Pernah nggak sih, lagi asik coding React, tiba-tiba muncul warning merah di console kayak gini?
”Warning: Can’t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application.”
Saya sering banget nemu ini pas lagi code review kerjaan teman-teman yang masih junior. Biasanya ini kejadian kalau kita jalanin proses asynchronous—kayak fetch data atau timer—tapi usernya keburu pindah halaman sebelum prosesnya kelar. Pas prosesnya selesai dan mau update state, eh komponennya udah nggak ada. React pun ngomel.
Hari ini saya mau sharing soal gimana cara ngatasin ini pakai Cleanup Function di useEffect.
Apa Itu Cleanup Function?
Di React functional component, useEffect itu andalan kita buat ngurusin side effects. Tapi ingat, useEffect itu bukan cuma buat nyalain sesuatu, tapi juga buat matiin-nya.
Cleanup function itu sebenernya cuma fungsi biasa yang kita return dari dalam useEffect.
useEffect(() => {
// 1. Logika effect jalan di sini
console.log("Component mounted atau updated");
return () => {
// 2. Logika cleanup jalan di sini
console.log("Component unmounted atau sebelum re-run effect");
};
}, []);
React bakal jalanin fungsi cleanup ini pas:
- Component mau di-unmount (hilang dari layar).
- Component mau re-render (sebelum jalanin effect yang baru).
Contoh Kasus: Timer Bandel
Biar gampang, kita ambil contoh klasik: bikin timer sederhana.
Cara yang Salah
Ini contoh kode yang sering bikin memory leak. Kita pasang timer, tapi lupa dimatiin.
import { useState, useEffect } from "react";
function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
console.log("Tick");
setCount((prev) => prev + 1);
}, 1000);
// Lupa cleanup nih!
}, []);
return <div>Count: {count}</div>;
}
Kalau saya mount component Timer ini, terus langsung pindah ke halaman lain, itu setInterval bakal tetep jalan terus di background. Dia bakal maksa manggil setCount padahal komponennya udah almarhum. Ini yang namanya memory leak.
Cara yang Benar
Solusinya gampang banget. Kita tinggal matiin interval-nya pas komponen di-unmount.
import { useState, useEffect } from "react";
function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
console.log("Tick");
setCount((prev) => prev + 1);
}, 1000);
// Ini dia cleanup function-nya
return () => {
clearInterval(intervalId);
console.log("Timer dibersihkan!");
};
}, []);
return <div>Count: {count}</div>;
}
Sekarang, begitu komponen di-unmount, React bakal manggil fungsi return kita tadi. clearInterval jalan, timer mati, dan aplikasi kita tetap sehat walafiat.
Kapan Harus Dipakai?
Saran saya, biasakan mikir soal cleanup setiap kali pakai:
- Event Listeners: Kalau ada
window.addEventListener, wajib adaremoveEventListener. - Timers:
setTimeoutdansetInterval. - Subscriptions: Kayak koneksi WebSocket atau observables.
Kesimpulan
Nanganin side effects dengan benar itu salah satu hal yang bedain junior developer sama yang udah senior. Bukan cuma soal fiturnya jalan, tapi soal kodenya robust (tangguh) dan nggak bikin browser user jadi lemot.
Jadi, besok-besok kalau nulis useEffect, coba tanya ke diri sendiri: “Ini perlu dibersihin nggak ya?”