SCALE — Build Lab
開発パターン · REACT PATTERN

トースト通知

CATEGORY開発パターン TYPEReact Pattern EFFORT60〜180分 DIFFICULTY
PRIMARY CODE
tsx
'use client';
import { createContext, useContext, useState, useCallback, ReactNode } from 'react';

type Toast = { id: number; type: 'success' | 'error' | 'warn' | 'info'; msg: string };
type Ctx = { push: (type: Toast['type'], msg: string) => void };

const ToastCtx = createContext<Ctx>({ push: () => {} });
export const useToast = () => useContext(ToastCtx);

export function ToastProvider({ children }: { children: ReactNode }) {
  const [toasts, setToasts] = useState<Toast[]>([]);
  const push = useCallback((type: Toast['type'], msg: string) => {
    const id = Date.now() + Math.random();
    setToasts((t) => [...t, { id, type, msg }]);
    setTimeout(() => setToasts((t) => t.filter((x) => x.id !== id)), 3500);
  }, []);

  const COLOR = {
    success: 'bg-emerald-500/90 text-white',
    error:   'bg-rose-500/90 text-white',
    warn:    'bg-amber-500/90 text-white',
    info:    'bg-indigo-500/90 text-white',
  };

  return (
    <ToastCtx.Provider value={{ push }}>
      {children}
      <div className="fixed bottom-4 right-4 z-50 space-y-2">
        {toasts.map((t) => (
          <div key={t.id} className={`${COLOR[t.type]} px-4 py-2 rounded-xl shadow-lg text-sm`}>
            {t.msg}
          </div>
        ))}
      </div>
    </ToastCtx.Provider>
  );
}

// 使い方:
// const { push } = useToast();
// push('success', '保存しました');
前提条件
Tailwind CSS v4TypeScript 5
USE CASES
  • 全アクション後の通知

トースト通知

:LiTarget: 用途

成功/エラー/警告のトースト通知パターン。自動消去・スタック対応。

:LiSparkle: 特徴

  • 自動消去
  • スタック表示
  • 4種類(success/error/warn/info)

:LiCode: コード(コピペ用)

'use client';
import { createContext, useContext, useState, useCallback, ReactNode } from 'react';

type Toast = { id: number; type: 'success' | 'error' | 'warn' | 'info'; msg: string };
type Ctx = { push: (type: Toast['type'], msg: string) => void };

const ToastCtx = createContext<Ctx>({ push: () => {} });
export const useToast = () => useContext(ToastCtx);

export function ToastProvider({ children }: { children: ReactNode }) {
  const [toasts, setToasts] = useState<Toast[]>([]);
  const push = useCallback((type: Toast['type'], msg: string) => {
    const id = Date.now() + Math.random();
    setToasts((t) => [...t, { id, type, msg }]);
    setTimeout(() => setToasts((t) => t.filter((x) => x.id !== id)), 3500);
  }, []);

  const COLOR = {
    success: 'bg-emerald-500/90 text-white',
    error:   'bg-rose-500/90 text-white',
    warn:    'bg-amber-500/90 text-white',
    info:    'bg-indigo-500/90 text-white',
  };

  return (
    <ToastCtx.Provider value={{ push }}>
      {children}
      <div className="fixed bottom-4 right-4 z-50 space-y-2">
        {toasts.map((t) => (
          <div key={t.id} className={`${COLOR[t.type]} px-4 py-2 rounded-xl shadow-lg text-sm`}>
            {t.msg}
          </div>
        ))}
      </div>
    </ToastCtx.Provider>
  );
}

// 使い方:
// const { push } = useToast();
// push('success', '保存しました');

:LiHandPointer: 使い方

対象プロジェクトに該当ファイルをコピーして、props を流し込むだけ。

:LiAlertCircle: 注意事項

  • 依存パッケージを忘れず追加