How to Build a Notification System with Claude Code
Learn how to build a notification system using Claude Code. Includes practical code examples and step-by-step guidance.
通知システムの構築をClaude Codeで効率化する
Webアプリにおける通知は、トースト表示からプッシュ通知、リアルタイム更新まで多岐にわたります。Claude Codeを使えば、これらを統合した通知基盤を短時間で構築できます。
トースト通知コンポーネントの実装
まずはアプリ内で使うトースト通知を作ります。
> ライブラリを使わずにトースト通知コンポーネントをReactで作って。
> success/error/warning/infoの4種類。自動で消える。スタック表示対応。
import { createContext, useContext, useState, useCallback, type ReactNode } from "react";
type ToastType = "success" | "error" | "warning" | "info";
interface Toast {
id: string;
type: ToastType;
message: string;
}
interface ToastContextType {
addToast: (type: ToastType, message: string) => void;
}
const ToastContext = createContext<ToastContextType | null>(null);
const TOAST_STYLES: Record<ToastType, string> = {
success: "bg-green-500 text-white",
error: "bg-red-500 text-white",
warning: "bg-yellow-500 text-black",
info: "bg-blue-500 text-white",
};
const TOAST_ICONS: Record<ToastType, string> = {
success: "✓",
error: "✕",
warning: "⚠",
info: "ℹ",
};
export function ToastProvider({ children }: { children: ReactNode }) {
const [toasts, setToasts] = useState<Toast[]>([]);
const addToast = useCallback((type: ToastType, message: string) => {
const id = crypto.randomUUID();
setToasts((prev) => [...prev, { id, type, message }]);
setTimeout(() => {
setToasts((prev) => prev.filter((t) => t.id !== id));
}, 4000);
}, []);
return (
<ToastContext.Provider value={{ addToast }}>
{children}
<div className="fixed bottom-4 right-4 flex flex-col gap-2 z-50">
{toasts.map((toast) => (
<div
key={toast.id}
className={`px-4 py-3 rounded-lg shadow-lg flex items-center gap-2 animate-slide-in ${TOAST_STYLES[toast.type]}`}
>
<span>{TOAST_ICONS[toast.type]}</span>
<span>{toast.message}</span>
<button
onClick={() => setToasts((prev) => prev.filter((t) => t.id !== toast.id))}
className="ml-2 opacity-70 hover:opacity-100"
>
✕
</button>
</div>
))}
</div>
</ToastContext.Provider>
);
}
export function useToast() {
const context = useContext(ToastContext);
if (!context) throw new Error("useToast must be used within ToastProvider");
return context;
}
WebSocketによるリアルタイム通知
サーバーからのリアルタイム通知を受け取る仕組みも構築できます。
// Server side(Node.js + ws)
import { WebSocketServer, WebSocket } from "ws";
interface Client {
ws: WebSocket;
userId: string;
}
const clients: Client[] = [];
const wss = new WebSocketServer({ port: 8080 });
wss.on("connection", (ws, req) => {
const userId = new URL(req.url!, `http://${req.headers.host}`).searchParams.get("userId");
if (!userId) return ws.close();
clients.push({ ws, userId });
ws.on("close", () => {
const index = clients.findIndex((c) => c.ws === ws);
if (index !== -1) clients.splice(index, 1);
});
});
// 特定ユーザーへの通知送信
export function sendNotification(userId: string, notification: object) {
clients
.filter((c) => c.userId === userId)
.forEach((c) => c.ws.send(JSON.stringify(notification)));
}
// Client sideのフック
import { useEffect, useRef, useCallback } from "react";
interface Notification {
id: string;
type: string;
title: string;
body: string;
}
export function useNotifications(userId: string, onNotification: (n: Notification) => void) {
const wsRef = useRef<WebSocket | null>(null);
const connect = useCallback(() => {
const ws = new WebSocket(`ws://localhost:8080?userId=${userId}`);
ws.onmessage = (event) => {
const notification = JSON.parse(event.data);
onNotification(notification);
};
ws.onclose = () => {
setTimeout(connect, 3000); // Reconnect
};
wsRef.current = ws;
}, [userId, onNotification]);
useEffect(() => {
connect();
return () => wsRef.current?.close();
}, [connect]);
}
通知の永続化と既読管理
通知をDBに保存して既読管理する機能も追加できます。
// Prismaスキーマから自動でAPI生成を依頼
// schema.prisma の内容をClaude Codeが読み取って実装
import { db } from "@/lib/database";
export async function getNotifications(userId: string) {
return db.notification.findMany({
where: { userId },
orderBy: { createdAt: "desc" },
take: 50,
});
}
export async function markAsRead(notificationId: string) {
return db.notification.update({
where: { id: notificationId },
data: { readAt: new Date() },
});
}
export async function getUnreadCount(userId: string) {
return db.notification.count({
where: { userId, readAt: null },
});
}
Claude Codeでの開発効率を上げるには生産性を3倍にする10のTipsを参考にしてください。フォームとの連携についてはフォームバリデーション設計も併せてご覧ください。
Summary
Claude Codeを使えば、トースト通知、リアルタイム通知、永続化まで含めた通知システム全体を効率的に構築できます。自然言語で要件を伝え、段階的に機能を追加していくのがおすすめです。
公式ドキュメントはClaude Codeから確認できます。
Related Posts
Mastering Claude Code Hooks: Auto-Format, Auto-Test, and More
Mastering Claude Code Hooks: Auto-Format, Auto-Test, and More. A practical guide with code examples.
Claude Code MCP Server Setup and Practical Use Cases
Claude Code MCP Server Setup and Practical Use Cases. A practical guide with code examples.
The Complete Guide to Writing CLAUDE.md: Best Practices for Project Configuration
The Complete Guide to Writing CLAUDE.md: Best Practices for Project Configuration. A practical guide with code examples.