"use client"; import { createContext, useCallback, useContext, useMemo, useState, type ReactNode, } from "react"; type ToastKind = "info" | "error" | "success"; interface ToastItem { id: number; message: string; kind: ToastKind; } type ShowToast = (message: string, kind?: ToastKind) => void; const ToastContext = createContext(null); const TOAST_TTL_MS = 4000; export function ToastProvider({ children }: { children: ReactNode }) { const [items, setItems] = useState([]); const show = useCallback((message, kind = "info") => { const id = Date.now() + Math.random(); setItems((prev) => [...prev, { id, message, kind }]); setTimeout(() => { setItems((prev) => prev.filter((t) => t.id !== id)); }, TOAST_TTL_MS); }, []); const value = useMemo(() => show, [show]); return ( {children}
{items.map((t) => (
{t.message}
))}
); } export function useToast(): ShowToast { const ctx = useContext(ToastContext); if (!ctx) { // 容错:未挂 Provider 时退化为 no-op(不应在生产路径发生)。 return () => undefined; } return ctx; }