Supabase Realtime ile React'te Canlı Veri Takibi
Supabase Realtime ile React'te gerçek zamanlı veri nasıl takip edilir? postgres_changes, broadcast, channel yönetimi ve memory leak önleme rehberi.
Gerçek Zamanlı Güncelleme Neden Önemli?
Dashboard’da satış verisi güncellendi — ama kullanıcı sayfayı yenilemeden görmüyor. Chat mesajı geldi — karşı taraf anlamıyor. Stok düştü — ilgili kişi saatler sonra fark ediyor.
Supabase Realtime bu sorunları WebSocket üzerinden çözer.
Temel Kullanım: Tablo Dinleme
import { useEffect, useState } from 'react';
import { supabase } from '../lib/supabase';
function LiveOrders() {
const [orders, setOrders] = useState<Order[]>([]);
useEffect(() => {
// Mevcut siparişleri çek
supabase.from('orders').select('*').order('created_at', { ascending: false })
.then(({ data }) => setOrders(data || []));
// Gerçek zamanlı dinlemeye başla
const channel = supabase
.channel('orders-changes')
.on(
'postgres_changes',
{ event: 'INSERT', schema: 'public', table: 'orders' },
(payload) => {
setOrders(prev => [payload.new as Order, ...prev]);
}
)
.on(
'postgres_changes',
{ event: 'UPDATE', schema: 'public', table: 'orders' },
(payload) => {
setOrders(prev => prev.map(o =>
o.id === payload.new.id ? payload.new as Order : o
));
}
)
.subscribe();
// Cleanup — memory leak önleme
return () => {
supabase.removeChannel(channel);
};
}, []);
return (
<ul>
{orders.map(order => (
<li key={order.id}>{order.customer} — ₺{order.total}</li>
))}
</ul>
);
}
Custom Hook: useRealtimeQuery
import { useEffect, useState, useCallback } from 'react';
import { supabase } from '../lib/supabase';
import { RealtimePostgresChangesPayload } from '@supabase/supabase-js';
export function useRealtimeQuery<T extends { id: string }>(
table: string,
query?: string
) {
const [data, setData] = useState<T[]>([]);
const [loading, setLoading] = useState(true);
// İlk veriyi çek
const fetchData = useCallback(async () => {
const { data: rows } = await supabase
.from(table)
.select(query || '*')
.order('created_at', { ascending: false });
setData((rows as T[]) || []);
setLoading(false);
}, [table, query]);
useEffect(() => {
fetchData();
const channel = supabase
.channel(`${table}-realtime`)
.on(
'postgres_changes',
{ event: '*', schema: 'public', table },
(payload: RealtimePostgresChangesPayload<T>) => {
if (payload.eventType === 'INSERT') {
setData(prev => [payload.new as T, ...prev]);
} else if (payload.eventType === 'UPDATE') {
setData(prev => prev.map(item =>
item.id === (payload.new as T).id ? payload.new as T : item
));
} else if (payload.eventType === 'DELETE') {
setData(prev => prev.filter(item =>
item.id !== (payload.old as T).id
));
}
}
)
.subscribe();
return () => { supabase.removeChannel(channel); };
}, [table, fetchData]);
return { data, loading, refetch: fetchData };
}
// Kullanım
function Dashboard() {
const { data: orders, loading } = useRealtimeQuery<Order>('orders');
if (loading) return <Skeleton />;
return <OrderTable data={orders} />;
}
RLS + Realtime Güvenliği
Realtime, RLS politikalarına tabidir. Kullanıcı sadece yetkili olduğu satırları alır:
-- Yalnızca kendi tenant'ının siparişlerini görsün
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY "tenant_orders" ON orders
FOR SELECT
USING (tenant_id = (auth.jwt() -> 'app_metadata' ->> 'tenant_id')::uuid);
⚠️ RLS olmadan tüm INSERT/UPDATE/DELETE eventleri tüm dinleyicilere gider!
Broadcast: Ephemeral Mesajlaşma
Database’e yazılmayan, anlık mesajlar:
// Cursor pozisyonu paylaşma (Google Docs gibi)
const channel = supabase.channel('room-1');
// Gönder
channel.send({
type: 'broadcast',
event: 'cursor',
payload: { x: 100, y: 200, user: 'Ahmet' },
});
// Dinle
channel.on('broadcast', { event: 'cursor' }, ({ payload }) => {
moveCursor(payload.x, payload.y, payload.user);
}).subscribe();
Dikkat Edilecekler
- Cleanup zorunlu:
useEffectreturn’ünderemoveChannelçağrın — yoksa memory leak. - Duplicate subscription: Component re-render’da yeni channel oluşmaz — dependency array doğru olmalı.
- Büyük tablolar: Tüm değişiklikleri dinlemeyin, filtre kullanın.
- Offline durumu: WebSocket koparsa Supabase otomatik reconnect yapar.
İlgili Yazılar
- PostgreSQL NOTIFY/LISTEN — Realtime’ın altyapısı
- Supabase Auth — Session + Realtime
- Supabase RLS — Realtime güvenliği
- React Query Cache — Realtime + cache senkronizasyonu
Bu rehber Supabase Realtime Docs dokümantasyonuna dayanarak hazırlanmıştır.