# Membangun Real-time Dashboard Skala Besar dengan React dan WebSocket

> Diterbitkan oleh Literally Web ID pada 21 Oct 2026
> Sumber: https://literally.web.id/articles/membangun-real-time-dashboard-skala-besar-dengan-react-dan-websocket

---

Pengalaman di lapangan mengajarkan saya satu hal pahit: membangun real-time dashboard yang menampilkan ribuan data per detik sering kali berujung pada bencana memori jika pondasinya rapuh. Suatu malam, saat peluncuran fitur trading kripto berskala besar, browser ribuan pengguna mendadak freeze karena WebSocket mengirim pesan mentah tanpa manajemen koneksi yang benar, sementara komponen React mengalami re-render beruntun hingga RAM server lokal jebol. Dari insiden malam itu, saya merumuskan sebuah peta jalan arsitektural yang kini saya rangkum dalam bentuk *Cheat Sheet & Decision Tree* agar Anda tidak perlu mengulang kesalahan yang sama.

## 1. Intisari Kilat: Fondasi dalam Sekali Lirik

Dalam membangun real-time dashboard berskala enterprise menggunakan React dan WebSocket, fokus kita bukan sekadar membuat data 'bisa tampil', melainkan bagaimana menjaga agar browser tidak mengalami *memory leak* dan UI tetap di 60 FPS saat ribuan *event* masuk per detik. 

Berikut adalah tiga pilar utama yang menjadi jangkar arsitektur kita:
- **Manajemen Koneksi WebSocket:** Jangan pernah membuka koneksi WebSocket di dalam komponen React secara langsung menggunakan `useEffect` mentah tanpa *singleton pattern* atau *custom hook* yang terisolasi. Gunakan pustaka stabil seperti `ReconnectingWebSocket` atau implementasikan *heartbeat ping/pong* manual untuk mendeteksi *dead connection* di balik load balancer Nginx.
- **Optimasi Re-render React:** Data berkecepatan tinggi akan membunuh React jika setiap *payload* masuk memicu `setState` pada komponen akar. Pisahkan state global koneksi dari state lokal komponen, manfaatkan *requestAnimationFrame* (rAF) untuk melakukan *batching state update*, dan bungkus komponen visual dengan `React.memo` yang dilengkapi *custom comparator*.
- **Fallback & Reconnection Strategy:** Internet pengguna tidak selalu stabil. Terapkan strategi *Exponential Backoff with Jitter* saat koneksi terputus agar server tidak diserang ribuan request simultan saat jaringan pulih. Sediakan juga mekanisme *fallback* ke HTTP Long-Polling jika port WebSocket diblokir oleh corporate firewall.

> [!IMPORTANT]
> Jangan pernah melakukan mutasi langsung pada objek state WebSocket atau Redux/Zustand di dalam *event listener* `onmessage`. Selalu buat kloning atau gunakan *immutable state updater* untuk mencegah race condition pada render cycle.

Memahami pilar-pilar ini barulah langkah awal. Pertanyaannya sekarang, kapan kita harus memilih arsitektur WebSocket murni, dan kapan kita harus berpindah ke alternatif lain seperti Server-Sent Events (SSE) atau gRPC-Web? Mari kita bedah melalui kompas keputusan di bawah ini.

## 2. Kompas Keputusan: Kapan Memilih Solusi Ini vs Alternatif Lain

Sebagai *Principal Engineer*, keputusan memilih teknologi harus didasarkan pada karakteristik arus data, bukan sekadar ikut tren. Gunakan *decision flow* berikut untuk menentukan arah:

1. **Apakah aliran data bersifat satu arah (Server ke Client saja, contoh: ticker harga, notifikasi, log streaming)?**
   - *Jika Ya:* Jangan gunakan WebSocket. Gunakan **Server-Sent Events (SSE)** karena didukung secara native oleh browser, otomatis melakukan *reconnection*, dan jauh lebih ringan di level Nginx/Proxy.
   - *Jika Tidak (butuh komunikasi dua arah seperti chat interaktif, trading interaktif, atau game state):* Lanjutkan ke pertanyaan berikutnya.

2. **Apakah frekuensi pengiriman data melebihi 10 pesan per detik per klien?**
   - *Jika Ya:* Gunakan **WebSocket** dengan arsitektur *Binary Protocol* (seperti Protobuf atau MessagePack) alih-alih JSON mentah untuk memangkas *payload size* dan beban parsing CPU di sisi browser.
   - *Jika Tidak:* Gunakan REST polling berkala atau GraphQL Subscriptions jika infrastruktur backend sudah berbasis GraphQL.

> [!TIP]
> Jika Anda berada di balik load balancer seperti AWS ALB (Application Load Balancer), pastikan *Idle Timeout* disesuaikan (misal 60 detik atau lebih) dan aktifkan *TCP Keep-Alive* agar koneksi WebSocket tidak terputus secara sepihak oleh infrastruktur cloud.

Setelah menentukan pilihan teknologi, mari kita lihat contekan konfigurasi konkret yang teruji di lingkungan produksi untuk memastikan kestabilan koneksi dan efisiensi memori.

## 3. Contekan Konfigurasi & Parameter Paling Sering Dicari

Berikut adalah ringkasan parameter krusial pada Nginx reverse proxy, konfigurasi sistem operasi Linux, serta cuplikan kode React hook untuk manajemen WebSocket yang aman dari memory leak.

```nginx
# Konfigurasi Nginx untuk WebSocket Proxying
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name dashboard.internal.system;

    location /ws/ {
        proxy_pass http://backend_upstream;
        proxy_http_version 1.1;
        
        # Header krusial untuk upgrade protokol
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $host;
        
        # Timeout panjang untuk menjaga koneksi tetap hidup
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        
        # Disable buffering agar data real-time tidak tertahan di buffer
        proxy_buffering off;
    }
}
```

```javascript
// Custom Hook React: useWebSocketStream.js (Aman dari Memory Leak & Re-render Berlebih)
import { useEffect, useRef, useState, useCallback } from 'react';

export function useWebSocketStream(url) {
    const [data, setData] = useState(null);
    const [status, setStatus] = useState('CONNECTING');
    const wsRef = useRef(null);
    const batchRef = useRef([]);
    const frameIdRef = useRef(null);

    // Batching update menggunakan requestAnimationFrame untuk performa 60 FPS
    const processBatch = useCallback(() => {
        if (batchRef.current.length > 0) {
            const latestData = batchRef.current[batchRef.current.length - 1];
            setData(latestData);
            batchRef.current = [];
        }
        frameIdRef.current = requestAnimationFrame(processBatch);
    }, []);

    useEffect(() => {
        const ws = new WebSocket(url);
        wsRef.current = ws;

        ws.onopen = () => setStatus('CONNECTED');
        ws.onclose = () => setStatus('DISCONNECTED');
        ws.onerror = (err) => console.error('WS Error:', err);
        
        ws.onmessage = (event) => {
            try {
                const parsed = JSON.parse(event.data);
                batchRef.current.push(parsed);
            } catch (e) {
                console.error('Gagal parsing JSON:', e);
            }
        };

        frameIdRef.current = requestAnimationFrame(processBatch);

        return () => {
            cancelAnimationFrame(frameIdRef.current);
            if (wsRef.current) {
                wsRef.current.close();
            }
        };
    }, [url, processBatch]);

    return { data, status, socket: wsRef.current };
}
```

> [!WARNING]
> Jangan pernah menggunakan `setInterval` di dalam komponen React untuk memperbarui state WebSocket tanpa membersihkannya (`clearInterval`). Hal ini adalah penyebab nomor satu *memory leak* pada dashboard web.

Pengaturan konfigurasi dan kode di atas adalah fondasi harian kita di server. Agar operasional berjalan cepat, mari kita simpan beberapa mantra terminal berikut di dalam kepala.

## 4. Koleksi Mantra One-Liner Siap Salin untuk Keseharian

Saat insiden terjadi di production, detik-detik sangat berharga. Gunakan kumpulan *one-liner* bash berikut untuk mendiagnosis masalah jaringan dan performa server:

```bash
# 1. Cek jumlah koneksi WebSocket aktif pada port 80/443 di server Linux
netstat -an | grep ESTABLISHED | grep -E ':80|:443' | wc -l

# 2. Monitor log Nginx secara real-time khusus untuk error WebSocket
tail -f /var/log/nginx/error.log | grep -i 'upstream timed out'

# 3. Uji koneksi WebSocket dari terminal menggunakan wscat
npm install -g wscat && wscat -c wss://dashboard.internal.system/ws/

# 4. Cek penggunaan memori proses Node.js backend yang menangani WebSocket
ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head -n 10
```

> [!TIP]
> Simpan perintah `wscat` di jump host Anda; alat ini sangat ampuh untuk memverifikasi apakah masalah koneksi berasal dari Nginx proxy atau dari kode aplikasi frontend React.

Namun, sehebat apapun mantra terminal Anda, satu baris kode yang salah di level frontend atau backend dapat meruntuhkan seluruh sistem. Mari kita waspadai jalur bahaya berikut.

## 5. Jalur Bahaya: Dosa Besar yang Wajib Dihindari di Produksi

Sebagai penutup dari catatan lapangan ini, catat baik-baik jebakan fatal yang harus dihindari tim engineering Anda:

- **Dosa 1: Membuka Koneksi di Setiap Sub-Komponen.** Jangan pernah memanggil `new WebSocket()` di dalam komponen anak (child components). Gunakan *React Context* atau *Zustand Store* yang membungkus satu instance koneksi global.
- **Dosa 2: Mengabaikan Backpressure.** Jika server mengirim data 1000 msg/sec sementara browser Anda hanya mampu merender 60 frame/sec, antrean memori browser akan meledak. Selalu terapkan *throttling*, *debouncing*, atau *requestAnimationFrame batching* seperti pada contoh kode di atas.
- **Dosa 3: Tidak Menggunakan Ping/Pong Keep-Alive.** Load balancer cloud (seperti AWS ALB atau Cloudflare) akan otomatis memutuskan koneksi TCP yang tampak 'diam' (idle) selama 60 detik. Pastikan backend Anda mengirim paket `ping` berkala dan frontend merespons dengan `pong`.

Dengan mematuhi peta jalan, konfigurasi, dan rambu-rambu bahaya di atas, dashboard real-time Anda tidak hanya akan berjalan mulus, tetapi juga kokoh menghadapi lonjakan trafik ribuan pengguna tanpa ampun. Selamat merancang sistem yang resilien!