useCallback — konsep kunci, hook memoization fungsi di React

Penulis: IT Sectr Diterbitkan: 2026-07-04 Waktu membaca: 9 mnt

useCallback — adalah hook React yang mengembalikan versi fungsi yang telah dimemoize, yang tidak berubah antar render selama dependensinya tidak berubah. Berbeda dengan deklarasi fungsi biasa di dalam komponen (yang membuat fungsi baru setiap render), useCallback menstabilkan referensi fungsi, sehingga mencegah re-render yang tidak perlu pada komponen anak yang dioptimalkan melalui React.memo. Menurut React Documentation (2025), useCallback hanya berguna jika dipadukan dengan React.memo atau hook yang bergantung pada referensi yang stabil.

Poin penting

  • useCallback — hook untuk memoization fungsi, yang mempertahankan referensi antar render.
  • React.memo — useCallback hanya efektif dipadukan dengan React.memo untuk mencegah re-render.
  • Dependensi — fungsi dibuat ulang hanya ketika nilai yang ditentukan di array berubah.
  • Referensi stabil — useCallback menjamin referensi fungsi tidak berubah tanpa kebutuhan.
  • Jangan berlebihan — useCallback yang berlebihan tanpa React.memo memperburuk kinerja.

Apa itu useCallback di React

useCallback — adalah hook yang ditambahkan di React 16.8 yang mememoize fungsi: mengembalikan referensi yang sama selama dependensi tidak berubah. Tanpa useCallback, setiap deklarasi fungsi di dalam komponen membuat objek fungsi baru setiap render. Untuk primitif hal ini tidak terlihat, tetapi saat mengirim callback semacam itu ke komponen anak yang dioptimalkan melalui React.memo, setiap referensi baru menyebabkan re-render komponen anak.

Secara sintaksis, useCallback setara dengan useMemo untuk fungsi: useCallback(fn, deps) — adalah singkatan dari useMemo(() => fn, deps). React menyimpan fungsi yang dimemoize di penyimpanan internal node fiber dan membandingkan dependensi setiap render. Jika dependensi tidak berubah (Object.is untuk setiap elemen), fungsi sebelumnya dikembalikan.

Menurut React Documentation — useCallback (2025), tidak perlu membungkus setiap fungsi dengan useCallback. Hook ini memiliki harga sendiri: pemanggilan hook, perbandingan dependensi, dan alokasi memori untuk array dependensi. Jika komponen sederhana dan tidak memiliki pohon yang dalam dengan React.memo — useCallback hanya akan memperlambat aplikasi. Optimasi harus terukur, bukan intuitif.

jsx
import { useCallback } from 'react';

function Parent() {
    const [count, setCount] = useState(0);

    // Referensi stabil — fungsi yang sama sampai deps berubah
    const handleClick = useCallback(() => {
        setCount(prev => prev + 1);
    }, []);

    return <Child onClick={handleClick} />;
}

Bagaimana cara kerja memoization fungsi

Memoization di useCallback didasarkan pada cache hasil pemanggilan fungsi. React menyimpan closure yang dibuat pada render pertama dan mengembalikannya pada render berikutnya selama dependensi tetap tidak berubah. Di dalam node fiber, setiap pemanggilan useCallback membuat node dalam daftar tertaut hook, tempat dependensi sebelumnya dan nilai yang dimemoize disimpan.

Proses perbandingan dependensi dilakukan secara ketat melalui Object.is — ini perbandingan dangkal, tanpa pemeriksaan mendalam pada objek atau array. Jika ada objek atau array di dependensi, referensi baru setiap render akan dianggap sebagai perubahan. Oleh karena itu, di array dependensi perlu mengirim nilai primitif atau referensi stabil (misalnya dari useRef atau useMemo).

Menurut React Core Team — Optimization Guide (2024), biaya memoization mencakup tiga komponen: alokasi array dependensi setiap render, perulangan dan perbandingan elemen melalui Object.is, serta overhead potensial dari garbage collection saat pembuatan ulang. Untuk komponen dengan ratusan pembungkus useCallback ini bisa menjadi nyata — oleh karena itu selektivitas dalam penggunaan hook sangat penting.

SkenarioTanpa useCallbackDengan useCallback
Pembuatan fungsiBaru setiap renderSama dengan deps stabil
Pengiriman ke React.memoAnak re-renderAnak tidak re-render
Di array useEffectEfek dijalankan ulangEfek stabil
OverheadMinimalPerbandingan dependensi + memori

useCallback dan kinerja

Ada mitos yang tersebar luas bahwa useCallback secara otomatis meningkatkan kinerja. Sebenarnya, dalam isolasi (tanpa React.memo) useCallback bahkan sedikit memperlambat aplikasi karena biaya perbandingan dependensi. Hook ini memberikan manfaat nyata hanya dalam tiga skenario: mencegah re-render komponen React.memo, stabilitas callback di useEffect, dan pengiriman ke custom hook yang bergantung pada reference equality.

Aturannya sederhana: selama kamu belum menemukan masalah kinerja melalui React DevTools Profiler — jangan gunakan useCallback. Tim React telah berulang kali menekankan bahwa optimasi prematur adalah akar kejahatan. Pertama tulis kode bersih tanpa memoization, ukur, temukan bottleneck di profiler, dan baru kemudian tambahkan useCallback di tempat yang benar-benar diperlukan.

jsx
// Optimasi terukur: Child dibungkus dengan React.memo
const Child = React.memo(({ onClick }) => {
    console.log('Child re-render');
    return <button onClick={onClick}>Click</button>;
});

function Parent() {
    const handleClick = useCallback(() => {
        console.log('diklik');
    }, []);
    return <Child onClick={handleClick} />;
}

Menurut Dan Abramov — Before You memo() (2024), lebih dari 90% kasus penggunaan useCallback di proyek open-source berlebihan. Pengembang membungkus setiap fungsi "untuk berjaga-jaga", tanpa mengukur efeknya. Alternatif: jika komponen anak berat dan re-rendernya mahal — React.memo + useCallback dibenarkan. Jika komponen anak ringan — re-render lebih murah daripada perbandingan dependensi.

Kapan menggunakan useCallback

Skenario pertama — React.memo. Jika komponen anak dibungkus dengan React.memo dan menerima fungsi callback sebagai prop, tanpa useCallback komponen anak akan digambar ulang setiap render induk, bahkan jika datanya sendiri tidak berubah. useCallback menstabilkan referensi, dan React.memo dapat melewati re-render dengan benar.

Skenario kedua — useEffect dengan callback di dependensi. Jika fungsi dikirim ke array dependensi useEffect, setiap referensi baru akan menjalankan ulang efek. useCallback menjamin referensi stabil, dan efek hanya dijalankan saat data nyata berubah, bukan setiap render. Ini sangat penting untuk subscription dan permintaan.

  • React.memo children — mencegah re-render komponen anak yang dimemoize saat mengirim callback.
  • useEffect dependencies — menstabilkan fungsi di array dependensi efek, mencegah eksekusi ulang yang berlebihan.
  • Custom hook — jika hook menerima callback dan bergantung pada reference equality-nya, useCallback wajib digunakan.
  • Context value — jika fungsi dikirim di value konteks, useMemo dengan useCallback menstabilkan referensi.
jsx
// useCallback untuk dependensi useEffect yang stabil
const fetchData = useCallback(async (id) => {
    const res = await fetch(`/api/${id}`);
    setData(res.data);
}, []); // referensi stabil, tidak pernah dibuat ulang

useEffect(() => {
    fetchData(props.id);
}, [props.id, fetchData]); // efek berjalan hanya saat props.id berubah

useCallback vs useMemo

Perbedaan utama antara useCallback dan useMemo terletak pada apa yang masing-masing memoize. useCallback mememoize fungsi: useCallback(fn, deps) mengembalikan fn (versi yang sama atau sebelumnya). useMemo mememoize hasil pemanggilan fungsi: useMemo(() => computeExpensive(a, b), [a, b]) mengembalikan nilai yang dihitung, bukan fungsi.

Secara teknis, useCallback adalah gula sintaksis di atas useMemo: useCallback(fn, deps) setara dengan useMemo(() => fn, deps). Sintaks ini ada hanya untuk keterbacaan — agar pengembang melihat dengan jelas bahwa yang dimemoize adalah fungsi, bukan nilai. Tidak ada perbedaan kinerja antara useCallback dan useMemo dengan fungsi — keduanya menghasilkan kode yang sama.

HookMemoizeSintaksisPenggunaan
useCallbackFungsi (referensi)useCallback(fn, deps)Callback untuk komponen anak
useMemoHasil perhitunganuseMemo(() => value, deps)Perhitungan mahal, memoization objek
jsx
// Ini setara:
const handleClick = useCallback(() => doSomething(a, b), [a, b]);
const handleClick = useMemo(() => () => doSomething(a, b), [a, b]);

Kesalahan umum dengan useCallback

Kesalahan paling umum — membungkus semua fungsi secara tidak masuk akal dengan useCallback tanpa React.memo pada komponen anak. Jika komponen anak tidak dibungkus dengan React.memo, komponen tersebut tetap akan re-render setiap render induk, terlepas dari apakah referensi callback berubah atau tidak. useCallback tanpa React.memo — biaya tanpa manfaat.

  • useCallback tanpa React.memo — komponen anak tetap re-render; optimasi tidak masuk akal.
  • Dependensi yang terlupakan — jika di dalam callback digunakan variabel yang tidak dicantumkan di deps, callback mengandung stale closure.
  • Memoization berlebihan — membungkus setiap fungsi, termasuk onClick trivial dengan console.log.
  • Objek dan array di dependensi — referensi baru setiap render dianggap perubahan, memoization sia-sia.
jsx
// ❌ Sia-sia: tidak ada React.memo di child
const handle = useCallback(() => doStuff(), []);
<Child onClick={handle} />; // Child tetap re-render tanpa React.memo

// ❌ Stale closure: dependensi hilang
const handle = useCallback(() => {
    console.log(count); // count selalu 0 — stale closure!
}, []);

// ✅ Benar: sertakan dependensi
const handle = useCallback(() => {
    console.log(count);
}, [count]);

Masalah stale closure di useCallback diselesaikan dengan mencantumkan semua variabel yang digunakan di array dependensi. eslint-plugin-react-hooks dengan exhaustive-deps secara otomatis memeriksa bahwa semua variabel dari tubuh callback ada di array. Jika callback menggunakan setState, yang tidak berubah antar render, dapat dengan aman dicantumkan di deps — React menjamin stabilitas setState.

Pertanyaan yang sering diajukan

Apakah perlu membungkus setiap fungsi dengan useCallback?

Tidak. useCallback masuk akal hanya dalam tiga kasus: komponen anak dibungkus dengan React.memo, fungsi digunakan di array dependensi useEffect, atau fungsi dikirim ke custom hook yang bergantung pada reference equality. Dalam kasus lain useCallback menambah overhead tanpa manfaat. Tim React merekomendasikan menulis tanpa optimasi terlebih dahulu dan menambahkannya berdasarkan hasil profiling.

Mana yang lebih cepat — useCallback atau fungsi baru setiap render?

Untuk komponen sederhana — fungsi baru setiap render sedikit lebih cepat, karena useCallback menghabiskan sumber daya untuk perbandingan dependensi dan alokasi array. Untuk komponen dengan pohon React.memo yang dalam — useCallback menang, mencegah re-render ribuan elemen anak. Ukur dan bandingkan, jangan menebak — gunakan React DevTools Profiler untuk penilaian objektif.

Bisakah useCallback digunakan dengan fungsi async?

Ya, useCallback bekerja dengan fungsi async persis sama seperti dengan fungsi sinkron. Hook mememoize fungsi itu sendiri, dan hasilnya (Promise) dikembalikan setiap kali dipanggil. Fungsi asinkron di dalam useCallback adalah pola umum untuk callback pemuatan data yang stabil yang digunakan di useEffect: const fetchData = useCallback(async (id) => {...}, []).

Bagaimana cara men-debug masalah useCallback dan React.memo?

Gunakan React DevTools Profiler — akan menunjukkan komponen mana yang re-render dan mengapa. Untuk pemeriksaan programatik tambahkan console.log atau useWhyDidYouUpdate — library yang mencatat penyebab re-render. Penyebab utama: prop berubah (termasuk referensi callback), state atau konteks berubah. Jika useCallback tidak membantu — periksa apakah semua dependensi sudah dicantumkan dengan benar.

Bagaimana mengirim useCallback ke komponen anak tanpa React.memo?

Bahkan tanpa React.memo, useCallback dapat berguna dalam kombinasi dengan useMemo untuk value konteks. Jika kamu mengirim objek dengan fungsi ke Context.Provider, bungkus pembuatan objek dengan useMemo, dan setiap fungsi dengan useCallback. Ini akan mencegah re-render semua konsumen konteks saat salah satu fungsi berubah. Tetapi untuk pengiriman callback langsung ke props tanpa React.memo, useCallback tidak bermanfaat.

Kesimpulan

  • useCallback — hook untuk memoization fungsi, yang mengembalikan referensi stabil hingga dependensi berubah.
  • React.memo synergy — useCallback hanya efektif dipadukan dengan React.memo pada komponen anak.
  • Perbandingan dependensi — melalui Object.is; objek/array di deps merusak memoization.
  • Ukur, jangan menebak — tambahkan useCallback hanya setelah menemukan bottleneck melalui profiler.
  • Stable closure — masukkan semua variabel yang digunakan ke array dependensi, jika tidak — stale closure.
  • useCallback vs useMemo — useCallback mememoize fungsi, useMemo — hasil perhitungan.
  • Keberlebihan — lebih dari 90% kasus penggunaan useCallback di proyek nyata adalah optimasi prematur.

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga