Skip to content

Optimasi Performa React: useMemo & useCallback

Posted on:January 9, 2026 at 10:00 AM

Halo, Sobat Ngoding! 👋

Pernah nggak sih bikin aplikasi React, awalnya kerasa cepet banget, “wus wus” gitu. Tapi begitu fitur nambah banyak, kok jadi berasa berat? Ketik satu huruf di form aja delay-nya minta ampun? Atau animasi jadi patah-patah?

Nah, di sinilah kita butuh yang namanya Optimasi Performa. Di dunia React, dua senjata andalan kita adalah useMemo dan useCallback.

Tapi hati-hati, banyak developer yang asal pake dua hooks ini di semua tempat karena dikira bakal bikin otomatis ngebut. Spoiler: kadang malah bikin tambah lambat lho! 😱

Yuk, sambil ngopi ☕, kita bedah bareng-bareng kapan dan gimana cara pake hooks ini dengan bener. Santai aja, nggak bakal pake bahasa alien kok.

Masalah Utama: Re-render itu “Murah”, tapi Hitungan itu Mahal

Pertama, kita harus paham cara kerja React. Setiap kali state berubah, React akan melakukan re-render. Artinya, dia menjalankan ulang fungsi komponen kita dari atas sampai bawah.

Biasanya, ini cepet banget. React itu pinter. Tapi, bayangin kalau di dalam komponen itu ada fungsi yang ngitung matematika super ribet:

const hitunganBerat = (num) => {
  console.log("Lagi mikir keras...");
  // Simulasi proses lemot (misal filter data ribuan baris)
  for (let i = 0; i < 1000000000; i++) {}
  return num * 2;
};

Kalau komponen kamu re-render gara-gara kamu ngetik di input field yang beda, fungsi hitunganBerat ini bakal jalan lagi. Padahal angka num-nya nggak berubah! Itu buang-buang tenaga, dan itulah yang bikin UI kamu jadi nge-freeze.


1. useMemo: Si Pengingat Hasil

useMemo itu ibarat buku catatan pintar. Dia tugasnya mengingat hasil dari sebuah perhitungan.

Analogi: Bayangin kamu nanya ke saya, “Berapa hasil 23.452 x 9.123?” Saya ambil kalkulator, ngitung 10 detik, terus kasih tau jawabannya. Kalau 5 detik kemudian kamu nanya pertanyaan yang persis sama, masa saya harus ngitung ulang pake kalkulator? Bodoh dong. Harusnya saya inget aja jawaban yang tadi.

Nah, itulah useMemo.

Cara Pakenya:

import { useState, useMemo } from 'react';

const KomponenBerat = () => {
  const [count, setCount] = useState(0);
  const [dark, setDark] = useState(false);

  // Tanpa useMemo, ini jalan TIAP render (bahkan pas ganti tema dark mode!)
  // const doubleNumber = hitunganBerat(count);

  // DENGAN useMemo:
  const doubleNumber = useMemo(() => {
    return hitunganBerat(count);
  }, [count]); // Cuma jalan kalau 'count' berubah

  const themeStyles = {
    backgroundColor: dark ? 'black' : 'white',
    color: dark ? 'white' : 'black'
  };

  return (
    <div style={themeStyles}>
      <input type="number" value={count} onChange={e => setCount(parseInt(e.target.value))} />
      <button onClick={() => setDark(prevDark => !prevDark)}>Ganti Tema</button>
      <div style={themeStyles}>{doubleNumber}</div>
    </div>
  );
}

Sekarang, kalau kamu klik “Ganti Tema”, komponen re-render buat update warna, tapi dia melewati proses hitungan berat tadi karena count nggak berubah. Mulus! ⚡


2. useCallback: Si Pengawet Fungsi

Yang ini agak tricky. Kalau useMemo nyimpen nilai (angka/objek), useCallback nyimpen definisi fungsi.

”Lho, buat apa nyimpen fungsi? Bikin fungsi kan gampang & cepet?”

Bener. Tapi di JavaScript, ada konsep Referential Equality (Kesamaan Referensi). Setiap kali komponen re-render, semua fungsi di dalamnya itu dianggap fungsi baru. Alamat memorinya beda, meskipun isinya sama.

Masalahnya: Kalau kamu oper fungsi ini sebagai props ke komponen anak (child) yang udah di-optimasi pake React.memo, si anak bakal bilang: “Woi, ada props baru nih! Fungsi baru! Aku harus re-render ulang!”

Cara Pakenya:

import { useState, useCallback } from 'react';
import ChildComponent from './ChildComponent';

const Parent = () => {
  const [count, setCount] = useState(0);
  const [toggle, setToggle] = useState(false);

  // Fungsi ini dibuat ulang tiap render
  // const increment = () => setCount(c => c + 1);

  // Fungsi ini bakal tetep sama alamatnya kecuali 'setCount' berubah (yang mana gak mungkin)
  const increment = useCallback(() => {
    setCount(c => c + 1);
  }, [setCount]);

  return (
    <div>
      <ChildComponent onIncrement={increment} />
      <button onClick={() => setToggle(!toggle)}>Toggle</button>
    </div>
  );
}

Di kasus ini, klik “Toggle” bikin Parent re-render. Tapi karena increment udah “diawetin” pake useCallback, si ChildComponent ngeliat props-nya masih sama, jadi dia nggak perlu re-render sia-sia.


Kapan JANGAN dipake? ⚠️

Mentang-mentang tau, jangan terus semua fungsi dibungkus useMemo sama useCallback ya. Kenapa?

  1. Kode jadi ribet: Susah dibaca temen setim.
  2. Makan memori: Kamu nuker kerja CPU dengan pemakaian RAM.
  3. Cost performa: Menjalankan logika “cek dependency” itu juga butuh waktu! Buat hitungan sepele (misal a + b), pake useMemo malah lebih lambat daripada ngitung langsung.

Aturan Main: Pake cuma kalau:

Penutup

Jadi gitu deh intinya:

Optimasi performa itu seni. Jangan optimasi di awal (premature optimization). Bikin dulu aplikasinya, ukur, kalau kerasa berat, baru keluarin jurus ini.

Selamat Ngoding! 🚀