使い方
使いたい箇所より上のコンポーネントに <ToastProvider>
を追加して(↓こんな感じ)、コンポーネント内で const toast = useToast();
で使う感じです。
createRoot(document.getElementById('root')!).render( <ToastProvider> <App /> </ToastProvider> );
const App = () => { const toast = useToast(); return <button onClick={() => toast('clicked!')}>toast</button> };
実装
import clsx from 'clsx'; import { PropsWithChildren, createContext, useContext, useState } from 'react'; const ToastContext = createContext<(message: string) => void>(() => {}); export const useToast = () => useContext(ToastContext); export const ToastProvider = ({ children }: PropsWithChildren) => { const [showsToast, setShowsToast] = useState(false); const [fadesOutToast, setFadesOutToast] = useState(false); const [toastMessage, setToastMessage] = useState(''); let toastHideTimerId: number | undefined = undefined; const toast = (message: string) => { clearTimeout(toastHideTimerId); setToastMessage(message); setShowsToast(true); toastHideTimerId = window.setTimeout(() => { setFadesOutToast(true); }, 3000); }; return ( <ToastContext.Provider value={toast}> {children} {showsToast && ( <div className={clsx('toast', { ['opacity-0 transition-all duration-300']: fadesOutToast, })} onTransitionEnd={() => { if (!fadesOutToast) { return; } setShowsToast(false); setFadesOutToast(false); }} > <div className="alert"> <span>{toastMessage}</span> </div> </div> )} </ToastContext.Provider> ); };