Membedah state sharing lanjutan di microfrontend: pola event bus dengan dokumen kontrak event, central store di host yang dibagikan via useSyncExternalStore, sinkronisasi store lokal remote, serta anti-pattern berbagi React context lintas remote.

Di episode 7 kita melihat dasar berbagi state. Sekarang kita masuk lebih dalam: bagaimana menangani event bus, central store, dan sinkronisasi di skala yang lebih kompleks, plus memahami apa yang jangan dilakukan (anti-pattern).
Mengapa penting? Karena state antar remote adalah titik paling rawan desain yang salah — dan kesalahan di sini sulit dilacak, sering muncul hanya di produksi saat banyak remote berinteraksi.
Event bus memakai window sebagai media: remote mempublikasikan kejadian dengan CustomEvent, yang lain mendengarkan. Ini de-couple antar remote — pengirim tidak perlu tahu siapa penerimanya.
Agar tidak kacau, dokumentasikan kontrak event: nama event + payload. Ini bentuk "API" antar remote di layer event.
| Event | Payload | Dipublikasikan oleh | Didengarkan oleh |
|---|---|---|---|
cart:updated | { cartCount } | cart | shell (badge) |
auth:changed | { user } | account/host | semua remote |
nav:goto | { path } | remote mana pun | shell (routing) |
export const Events = {
cartUpdated: 'cart:updated',
authChanged: 'auth:changed',
navGoto: 'nav:goto',
} as constDengan kontrak yang terdokumentasi di shared-state, semua tim memakai nama & payload yang sama.
Pendekatan lain: satu store di host (zustand/Redux) yang dibagikan ke remote. Supaya remote reaktif tanpa memecah singleton React context, host bisa memakai useSyncExternalStore dan meneruskan value via props.
import { useSyncExternalStore } from 'react'
import { useCartStore } from 'shared-state'
function Shell() {
const cartCount = useSyncExternalStore(
useCartStore.subscribe,
() => useCartStore.getState().cartCount,
)
return <CartApp cartCount={cartCount} onUpdate={useCartStore.getState().addToCart} />
}Remote menerima cartCount dan callback sebagai props — tidak perlu mengakses store langsung, sehingga terisolasi.
Tidak semua state harus di host. Sering lebih baik remote punya store lokal sendiri untuk state internalnya, dan hanya sinkronkan data minimal via event (misal total cart count) — bukan seluruh state.
Ini mengurangi kopling: remote mandiri, dan hanya "jumlah ringkasan" yang dibagikan. Contoh: checkout punya store lokal untuk detail pembayaran, tapi hanya mengirim checkout:complete saat selesai.
Tip
Gulirkan: kirim data minimal yang memang dibutuhkan konsumen lintas remote. Detail internal tetap lokal di remote masing-masing — ini menjaga independensi dan mempermudah penggantian remote.
Satu kesalahan fatal: berbagi langsung React Context antar remote. React Context bergantung pada instans React (fiber) — jika melewati batas bundle/microfrontend, context provider dan consumer bisa berada di instans berbeda dan tidak saling terhubung, atau memecah singleton.
Warning
Jangan mengandalkan React Context sebagai jembatan state antar remote. Context hanya aman di dalam satu aplikasi. Lintas remote, gunakan props, callbacks, atau event bus — bukan context.
Sebagai gantinya: pakai props (dari host ke remote), event bus (untuk notifikasi lintas remote), atau external store yang di-subscribe via useSyncExternalStore.
Pada episode 18 ini, kalian telah memahami state sharing lanjutan.
Inti yang harus dibawa pulang:
useSyncExternalStore + props, bukan context.Di episode 19 selanjutnya, kita akan membahas monorepo scaling: Nx/Turborepo & caching — pnpm workspaces, Turborepo task cache, Nx dependency graph & affected builds, remote cache di CI, dan kapan memilih monorepo vs standalone. Pastikan state kalian rapi!