第2章:Supabase Realtime 実践 - データベースの変更を監視しフロントエンドUIを自動更新

SupabaseはFirebaseの最強オープンソース代替品として知られ、その殺し文句の一つが Supabase Realtime 機能です。

従来の開発では「誰かがデータを追加すると、画面上に即時反映される」機能を実装するには、Socket.ioサーバーの構築、接続/切断/再接続の処理、複数ノード間の状態同期などが必要でした。Supabaseではこれら全てが数行のJavaScriptコードに凝縮されています。

ステップ1:Supabase管理画面でRealtime権限を有効化

パフォーマンスとセキュリティの観点から、SupabaseではRealtime機能がデフォルトで無効になっています。どのテーブルをブロードキャスト対象にするか明示的に指定する必要があります。

  1. Supabaseプロジェクトダッシュボードにログイン
  2. 左メニューの Database > Replication に移動
  3. Source セクションで 0 tables(または現在の数字)をクリック
  4. 監視対象のテーブルを選択(例:チャットメッセージ用の chat_messages テーブル)
  5. トグルスイッチをONに切り替え

ステップ2:フロントエンドで監視チャネルを作成

Next.jsフロントエンドプロジェクトに戻ります。 チャットルームコンポーネント ChatRoom.tsx があり、messages というuseStateで画面表示用のメッセージを管理していると仮定します。

Supabaseに「専用ブロードキャストチャネル」を登録する useEffect を追加します。

"use client"
import { useEffect, useState } from "react"
import { createClient } from "@/utils/supabase/client"

export default function ChatRoom() {
  const [messages, setMessages] = useState<any[]>([])
  const supabase = createClient()

  useEffect(() => {
    // 1. チャネル名を定義('public-chat'など任意の名前)
    const channel = supabase.channel('public-chat')

    // 2. Postgresの変更イベント(INSERT)を購読
    channel.on(
      'postgres_changes',
      {
        event: 'INSERT',           // 「追加」イベントのみ監視
        schema: 'public',          // デフォルトschema
        table: 'chat_messages'     // 監視対象テーブル指定
      },
      (payload) => {
        // 3. データベースに新規データが追加されるとこのコールバックが発火
        console.log("新しいメッセージを受信:", payload.new)
        
        // 新しいメッセージをReactのStateに追加し、画面再描画をトリガー
        // 注意:クロージャートラップを避けるため関数型のsetMessagesを使用
        setMessages((prevMessages) => [...prevMessages, payload.new])
      }
    )
    // 4. 購読接続を開始
    .subscribe((status) => {
      console.log("接続状態:", status);
    })

    // 5. クリーンアップ関数:ページ離脱時にチャネル購読を解除
    return () => {
      supabase.removeChannel(channel)
    }
  }, [])

  // チャット画面のレンダリング
  return (
    <div className="flex flex-col w-full max-w-2xl mx-auto h-[600px] border border-gray-200 rounded-2xl shadow-xl overflow-hidden bg-white">
      <div className="bg-primary text-white p-4 font-bold">
        🌐 グローバルチャットルーム
      </div>
      <div className="flex-1 p-4 overflow-y-auto bg-gray-50 flex flex-col gap-3">
        {messages.map((msg) => (
          <div key={msg.id} className="self-start max-w-[80%]">
            <span className="text-xs text-gray-500 mb-1 ml-1">{msg.sender_name}</span>
            <div className="bg-white p-3 rounded-2xl rounded-tl-none shadow-sm text-gray-800">
              {msg.content}
            </div>
          </div>
        ))}
      </div>
    </div>
  )
}

ステップ3:リアルタイム機能をテスト

このコードの魔法を体感しましょう:

  1. 2つの異なるブラウザウィンドウ(ChromeとSafariなど)でチャットルームページを開く
  2. Supabase管理画面のTable Editorから chat_messages テーブルに直接データを追加
  3. 0.1秒未満で両ウィンドウに同時に新しいメッセージが表示されます(F5リロード不要!)

裏側では fetch によるポーリングも、大規模なSocket.ioサーバーも一切不要です。クラウドとブラウザ間のWebSocket接続だけで実現されています。

技術解説:内部動作の仕組み

.subscribe() を実行すると、Supabase JS SDKはバックグラウンドでWebSocket接続を確立します。

Supabaseサーバー内部では、PostgreSQLの「WAL(Write-Ahead Logging)」を監視するElixir製モジュールが動作しており、データベースの変更を即時JSON形式に変換し、該当テーブルを購読中の全クライアントに配信します。

トラブルシューティング:通知が受信できない場合

実装通りに作動しない場合、以下の3点を確認してください:

  1. Replicationが有効になっていない(90%の初心者が陥る)。ラジオの電波が送信されていない状態です。
  2. RLS(Row Level Security)の制限:RLSが有効で、anonユーザーや認証ユーザー向けの適切なPolicyがない場合、通知がブロックされます。
  3. State更新ロジックの誤りsetMessages([...messages, payload.new]) と書くとクロージャートラップが発生し、常に最新1件しか保持されません。必ず関数型の setMessages(prev => [...prev, new]) を使用してください

この技術をマスターすれば、株価表示システムや共同編集ツールの開発基盤が整います。次章では難易度を上げ、AI APIを組み合わせたタイプライター風ストリーミング効果を実装します。

完全なチュートリアルをロック解除

このチャプターは有料コンテンツです。プロジェクトに参加して、10以上の神レベルのPromptや実際のソースコード例を含む、5000字以上の深い分析をロック解除してください!