Kodax

Real-time Subscriptions — Supabase

الاشتراكات في الوقت الحقيقي (Realtime)

بدل أن يسأل التطبيق الخادم كل ثانية "هل هناك جديد؟"، يفتح اتصالاً دائماً (WebSocket) ويستقبل التغييرات لحظة حدوثها: رسائل الدردشة، الإشعارات، لوحات المتابعة، التحرير المشترك.

ثلاثة أنواع

| النوع | ما ينقله | مثال |

|---|---|---|

| Postgres Changes | تغييرات الجداول (INSERT/UPDATE/DELETE) | رسالة جديدة حُفظت في قاعدة البيانات |

| Broadcast | رسائل بين العملاء دون حفظ | "فلان يكتب الآن..."، مؤشر الفأرة في تحرير مشترك |

| Presence | من متصل الآن | قائمة المتصلين في غرفة |

تغييرات الجداول

import { supabase } from "./supabaseClient.js";

export function subscribeToRoom(roomId, onMessage) {
  const channel = supabase
    .channel(`room-${roomId}`)
    .on(
      "postgres_changes",
      { event: "INSERT", schema: "public", table: "messages", filter: `room_id=eq.${roomId}` },
      (payload) => onMessage(payload.new)
    )
    .subscribe();
  return () => supabase.removeChannel(channel);   // استدعها عند مغادرة الغرفة
}

- فعّل الجدول للوقت الحقيقي أولاً: Database ← Publications ← supabase_realtime (أو ALTER PUBLICATION supabase_realtime ADD TABLE messages;).

- filter يقلل البيانات المرسلة (ويقلل الاستهلاك).

- payload.new الصف الجديد، و payload.old القديم (لـ UPDATE و DELETE؛ يحتاج REPLICA IDENTITY FULL للحصول على كل أعمدته).

الأمان

تغييرات الجداول تحترم RLS: المشترك يستقبل فقط الصفوف التي تسمح له سياسات SELECT برؤيتها. بدون RLS، أي شخص يستطيع الاستماع لكل التغييرات. قنوات Broadcast و Presence الخاصة تُحمى بتفعيل خيار القنوات الخاصة وسياسات على realtime.messages.

إلغاء الاشتراك

اشتراك لا يُلغى = تسرب اتصالات وذاكرة، وأحداث مكررة عند العودة للشاشة. في React:

// useEffect(() => subscribeToRoom(roomId, addMessage), [roomId]);
// الدالة المُعادة من subscribeToRoom تُستدعى تلقائياً عند التفكيك أو تغيير الغرفة
const cleanupPattern = "useEffect(() => subscribe(...), [deps])";
console.log(cleanupPattern);

نمط شائع: الجلب ثم الاشتراك

1. اجلب آخر 50 رسالة بـ select.

2. اشترك في INSERT الجديدة وأضفها للقائمة.

3. احذر التكرار: رسالة أُرسلت بين الخطوتين قد تصل مرتين — ميّزها بالمعرّف.

تمرين

ابنِ غرفة دردشة: جلب آخر الرسائل، الاشتراك في الجديدة، مؤشر "يكتب الآن" بـ Broadcast، وقائمة المتصلين بـ Presence. تأكد من إلغاء الاشتراكات عند مغادرة الصفحة.

// ===== الاشتراك في تغييرات جدول =====
const subscription = supabase
  .channel('public:messages')
  .on('postgres_changes', 
    { event: '*', schema: 'public', table: 'messages' },
    (payload) => {
      console.log('تغيير:', payload);
      
      if (payload.eventType === 'INSERT') {
        console.log('رسالة جديدة:', payload.new);
      }
    }
  )
  .subscribe();

// ===== الاشتراك في INSERT فقط =====
const messagesSubscription = supabase
  .channel('new-messages')
  .on('postgres_changes',
    { event: 'INSERT', schema: 'public', table: 'messages' },
    (payload) => {
      // أضف الرسالة الجديدة للقائمة
      setMessages(prev => [...prev, payload.new]);
    }
  )
  .subscribe();

// ===== مع فلتر =====
const myMessages = supabase
  .channel('my-messages')
  .on('postgres_changes',
    { 
      event: '*', 
      schema: 'public', 
      table: 'messages',
      filter: 'user_id=eq.123'
    },
    (payload) => {
      console.log('رسالتي:', payload);
    }
  )
  .subscribe();

// ===== إلغاء الاشتراك =====
supabase.removeChannel(subscription);
اختبر فهمك