78 lines
1.6 KiB
TypeScript
78 lines
1.6 KiB
TypeScript
/**
|
||
* useToast Hook
|
||
*
|
||
* 统一的Toast通知管理Hook
|
||
* 提供显示和关闭Toast的功能
|
||
* 支持成功和错误两种类型
|
||
* 自动管理Toast的显示和隐藏
|
||
*
|
||
* @created 2025-01-XX(从 page.tsx 提取)
|
||
* @hook
|
||
*/
|
||
|
||
'use client'
|
||
|
||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||
|
||
export type ToastType = 'success' | 'error'
|
||
|
||
export interface ToastState {
|
||
id: number
|
||
message: string
|
||
type: ToastType
|
||
}
|
||
|
||
interface UseToastOptions {
|
||
duration?: number
|
||
}
|
||
|
||
export function useToast(options: UseToastOptions = {}) {
|
||
const { duration = 3000 } = options
|
||
const [toast, setToast] = useState<ToastState | null>(null)
|
||
const timerRef = useRef<NodeJS.Timeout | null>(null)
|
||
const idRef = useRef(0)
|
||
|
||
const dismissToast = useCallback(() => {
|
||
if (timerRef.current) {
|
||
clearTimeout(timerRef.current)
|
||
timerRef.current = null
|
||
}
|
||
setToast(null)
|
||
}, [])
|
||
|
||
useEffect(() => {
|
||
if (!toast) return undefined
|
||
if (timerRef.current) {
|
||
clearTimeout(timerRef.current)
|
||
}
|
||
timerRef.current = setTimeout(() => {
|
||
setToast(null)
|
||
timerRef.current = null
|
||
}, duration)
|
||
return () => {
|
||
if (timerRef.current) {
|
||
clearTimeout(timerRef.current)
|
||
timerRef.current = null
|
||
}
|
||
}
|
||
}, [toast, duration])
|
||
|
||
const showToast = useCallback((message: string, type: ToastType = 'success') => {
|
||
idRef.current += 1
|
||
setToast({
|
||
id: idRef.current,
|
||
message,
|
||
type,
|
||
})
|
||
}, [])
|
||
|
||
return {
|
||
toast,
|
||
showToast,
|
||
dismissToast,
|
||
}
|
||
}
|
||
|
||
export type UseToastReturn = ReturnType<typeof useToast>
|
||
|