2.6 KiB

实时功能

监听数据变化

启用表的实时功能

重要:需要监听数据实时变化的数据表必须先通过以下指令启动 RealTime 功能

ALTER PUBLICATION supabase_realtime ADD TABLE public.messages;

监听变化

import { supabase } from 'src/supabase/client.ts';

const currentUserId = getCurrentUserId(); // 获取当前用户ID

const channel = supabase
  .channel('messages')
  .on(
    'postgres_changes',
    { event: 'INSERT', schema: 'public', table: 'messages' },
    (payload) => {
      const newMessage = payload.new;
      // 只处理其他用户发送的消息,避免重复显示自己的消息
      if (newMessage.user_id !== currentUserId) {
        setMessages(prev => [...prev, newMessage]);
      }
    }
  )
  .subscribe();

// 发送消息的正确做法
const sendMessage = async (content) => {
  // 1. 立即添加到本地状态(避免延迟)
  const tempMessage = { id: `temp-${Date.now()}`, content, user_id: currentUserId };
  setMessages(prev => [...prev, tempMessage]);

  // 2. 发送到数据库
  const { data, error } = await supabase.from('messages').insert({ content, user_id: currentUserId });
  if (error) {
    // 发送失败时移除本地消息
    setMessages(prev => prev.filter(msg => msg.id !== tempMessage.id));
  }
};

// ✅ 清理以防止内存泄漏
return () => { channel.unsubscribe(); };

注意事项

  • 记得为实时表设置适当的 RLS 策略
  • 发送消息成功后,立即手动将新消息对象添加到本地 messages 数组,不要依赖 Realtime 订阅来显示自己发送的消息(避免延迟)
  • Realtime 订阅仅用于接收其他用户发送的消息

用户在线状态

Supabase 提供实时功能来跟踪用户在线状态并在用户间共享状态。

const roomOne = supabase.channel('room_01');

// 同步和跟踪状态
roomOne
  .on('presence', { event: 'sync' }, () => {
    const newState = roomOne.presenceState();
    console.log('sync', newState);
  })
  .on('presence', { event: 'join' }, ({ key, newPresences }) => {
    console.log('join', key, newPresences);
  })
  .on('presence', { event: 'leave' }, ({ key, leftPresences }) => {
    console.log('leave', key, leftPresences);
  })
  .subscribe();

// 发送状态
const userStatus = {
  user: 'user-1',
  online_at: new Date().toISOString(),
};

roomOne.subscribe(async (status) => {
  if (status !== 'SUBSCRIBED') return;
  const presenceTrackStatus = await roomOne.track(userStatus);
  console.log(presenceTrackStatus);
});

// ✅ 清理以防止内存泄漏
return () => { roomOne.unsubscribe(); };