第2章:Supabase Realtime 実践 - データベースの変更を監視しフロントエンドUIを自動更新
SupabaseはFirebaseの最強オープンソース代替品として知られ、その殺し文句の一つが Supabase Realtime 機能です。
従来の開発では「誰かがデータを追加すると、画面上に即時反映される」機能を実装するには、Socket.ioサーバーの構築、接続/切断/再接続の処理、複数ノード間の状態同期などが必要でした。Supabaseではこれら全てが数行のJavaScriptコードに凝縮されています。
ステップ1:Supabase管理画面でRealtime権限を有効化
パフォーマンスとセキュリティの観点から、SupabaseではRealtime機能がデフォルトで無効になっています。どのテーブルをブロードキャスト対象にするか明示的に指定する必要があります。
- Supabaseプロジェクトダッシュボードにログイン
- 左メニューの Database > Replication に移動
- Source セクションで
0 tables(または現在の数字)をクリック - 監視対象のテーブルを選択(例:チャットメッセージ用の
chat_messagesテーブル) - トグルスイッチを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:リアルタイム機能をテスト
このコードの魔法を体感しましょう:
- 2つの異なるブラウザウィンドウ(ChromeとSafariなど)でチャットルームページを開く
- Supabase管理画面のTable Editorから
chat_messagesテーブルに直接データを追加 - 0.1秒未満で両ウィンドウに同時に新しいメッセージが表示されます(F5リロード不要!)
裏側では fetch によるポーリングも、大規模なSocket.ioサーバーも一切不要です。クラウドとブラウザ間のWebSocket接続だけで実現されています。
技術解説:内部動作の仕組み
.subscribe() を実行すると、Supabase JS SDKはバックグラウンドでWebSocket接続を確立します。
Supabaseサーバー内部では、PostgreSQLの「WAL(Write-Ahead Logging)」を監視するElixir製モジュールが動作しており、データベースの変更を即時JSON形式に変換し、該当テーブルを購読中の全クライアントに配信します。
トラブルシューティング:通知が受信できない場合
実装通りに作動しない場合、以下の3点を確認してください:
- Replicationが有効になっていない(90%の初心者が陥る)。ラジオの電波が送信されていない状態です。
- RLS(Row Level Security)の制限:RLSが有効で、anonユーザーや認証ユーザー向けの適切なPolicyがない場合、通知がブロックされます。
- State更新ロジックの誤り:
setMessages([...messages, payload.new])と書くとクロージャートラップが発生し、常に最新1件しか保持されません。必ず関数型のsetMessages(prev => [...prev, new])を使用してください。
この技術をマスターすれば、株価表示システムや共同編集ツールの開発基盤が整います。次章では難易度を上げ、AI APIを組み合わせたタイプライター風ストリーミング効果を実装します。