Belajar Zustand - Performance & Transient Updates
Episode 13 of 23

Belajar Zustand - Performance & Transient Updates

Episode ini membahas cara mengontrol re-render: selector yang mengembalikan nilai primitif, useShallow untuk beberapa slice, dan menghindari object baru di dalam selector. Kalian juga belajar transient updates dengan subscribe dan ref untuk memperbarui nilai seperti progress bar tanpa memicu render.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Pendahuluan

Zustand cepat karena selektif, tapi kecepatan itu hilang jika selector ditulis asal. Episode 13 membahas cara mengukur dan mengontrol re-render: memilih slice state yang tepat, memakai useShallow untuk beberapa nilai, dan menghindari jebakan object baru yang membuat store terlihat selalu berubah. Kita juga membahas transient updates — memperbarui nilai seperti posisi mouse tanpa re-render sama sekali.

Dengan kombinasi selector yang benar dan transient updates, aplikasi tetap responsif meski state diperbarui puluhan kali per detik.

Mengontrol Re-render dengan Selector

Selector yang Tepat

Zustand membandingkan hasil selector dengan strict equality. Perubahan state hanya memicu re-render jika nilai yang dikembalikan selector berbeda dari sebelumnya:

JSSelector atomik
const count = useCounter((s) => s.count)
const name = useCounter((s) => s.user.name)

useCounter((s) => s.count) mengembalikan nilai primitif sehingga perbandingan akurat. Selama count tidak berubah, komponen ini tidak re-render walau field lain dalam store berubah.

useShallow untuk Beberapa Slice

Untuk memilih beberapa nilai sekaligus tanpa re-render berlebihan, gunakan useShallow. Tanpa useShallow, object yang dikembalikan selector selalu baru sehingga komponen re-render terus-menerus:

JSuseShallow membandingkan nilai secara dangkal
import { useShallow } from 'zustand/react/shallow'
 
const { count, name } = useCounter(
  useShallow((s) => ({ count: s.count, name: s.name })),
)

useShallow((s) => ({ ... })) membandingkan tiap properti dengan Object.is. Object baru tetap dibuat, tapi re-render hanya terjadi jika nilai di dalamnya benar-benar berubah.

Menghindari Object Baru Setiap Render

Selector yang mengembalikan object atau array baru setiap dipanggil adalah penyebab paling umum re-render tak berujung. Contoh yang bermasalah:

JSSelector object baru setiap render
const user = useUser((s) => ({ name: s.name, age: s.age }))

Walau name dan age tidak berubah, object literal baru diciptakan tiap render sehingga strict equality selalu gagal. Solusinya pakai useShallow, atau pilih nilai primitif secara terpisah. Aturan mudahnya: jangan pernah membuat object di dalam selector tanpa useShallow.

Transient Updates

subscribe dan Ref

Tidak semua perubahan state perlu render. Posisi mouse, progress scroll, atau video playback bisa diperbarui puluhan kali per detik — me-render komponen untuk setiap frame adalah pemborosan. Zustand menyediakan subscribe untuk pola transient:

JSProgress bar tanpa re-render
import { useEffect, useRef } from 'react'
import { useProgressStore } from './stores/progress'
 
function ProgressBar() {
  const ref = useRef<HTMLDivElement>(null)
 
  useEffect(() => {
    const unsubscribe = useProgressStore.subscribe(
      (s) => s.progress,
      (progress) => {
        if (ref.current) {
          ref.current.style.width = `${progress}%`
        }
      },
    )
    return unsubscribe
  }, [])
 
  return <div ref={ref} className="progress-bar" />
}

useProgressStore.subscribe(selector, listener) mendaftarkan listener yang berjalan saat nilai progress berubah. Komponen hanya render satu kali; pembaruan berikutnya menulis langsung ke DOM via ref tanpa melalui React.

Pola getInitialState

Selector getInitialState menyediakan nilai awal yang dikembalikan subscribe saat listener pertama kali dipanggil — berguna untuk inisialisasi ref:

JSgetInitialState untuk nilai awal
useEffect(() => {
  const unsubscribe = useProgressStore.subscribe(
    (s) => s.progress,
    (progress) => {
      if (ref.current) {
        ref.current.style.width = `${progress}%`
      }
    },
    { fireImmediately: true },
  )
  return unsubscribe
}, [])

{ fireImmediately: true } memanggil listener segera dengan nilai terkini. Cocok ketika komponen me-mount di tengah-tengah proses, bukan dari awal.

Penutup

Episode 13 membahas senjata performa Zustand: selector yang memilih nilai kecil, useShallow untuk beberapa slice, menghindari object baru di dalam selector, dan transient updates yang memperbarui DOM tanpa render melalui subscribe plus ref.

Inti yang harus dibawa pulang:

  • Strict equality menentukan kapan komponen re-render.
  • Selector sebaiknya mengembalikan nilai primitif.
  • useShallow membandingkan properti object secara dangkal.
  • Object literal di dalam selector menyebabkan re-render tak berujung tanpa useShallow.
  • subscribe plus ref memungkinkan transient update tanpa render.
  • fireImmediately mengeksekusi listener dengan nilai awal saat subscribe.

Di episode 14 selanjutnya kita akan membahas SSR, React 19, dan integrasi framework — memakai Zustand dengan aman di Next.js App Router, menghindari perbedaan state saat hydration, integrasi hook use di React 19, serta store per-scope dengan Context.

Belajar Zustand - Performance & Transient Updates | Belajar Zustand