You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 13.4中shadcnUI Toast自定义duration不生效问题求助

解决方案:shadcnUI Toast 自定义 duration 不生效问题

1. 核心问题定位

进度条动画时长、Toast 移除定时器都硬绑定了全局默认的 5000ms,没有读取每个 Toast 实例传入的自定义 duration 值,导致自定义时长失效。

2. 具体修复步骤

(1)修正 use-toast.ts 中的 Toast 创建逻辑

确保每个 Toast 实例存储自定义的 duration,并在移除队列中使用该值:

// use-toast.ts
import { useState, useCallback } from 'react'
import type { Toast, ToastProps } from './toast'

const TOAST_REMOVE_DELAY = 5000 // 保留默认值,但不再强制全局使用

export function useToast() {
  const [toasts, setToasts] = useState<Toast[]>([])

  const createToast = useCallback((props: ToastProps) => {
    const id = crypto.randomUUID()
    // 优先使用传入的 duration,否则用默认值
    const toast: Toast = {
      id,
      duration: props.duration ?? TOAST_REMOVE_DELAY,
      ...props,
    }
    setToasts(prev => [...prev, toast])
    addToRemoveQueue(id)
    return id
  }, [])

  const addToRemoveQueue = useCallback((toastId: string) => {
    const targetToast = toasts.find(t => t.id === toastId)
    if (!targetToast) return
    // 使用当前 Toast 实例的 duration 而非全局常量
    setTimeout(() => {
      removeToast(toastId)
    }, targetToast.duration)
  }, [toasts])

  const removeToast = useCallback((toastId: string) => {
    setToasts(prev => prev.filter(t => t.id !== toastId))
  }, [])

  return {
    toast: createToast,
    removeToast,
    toasts,
  }
}

(2)修改 Toast 组件的进度条动画绑定

让进度条的过渡时长与当前 Toast 的 duration 同步:

// toast.tsx
import { useEffect, useRef } from 'react'
import type { Toast } from './use-toast'

interface ToastProps {
  toast: Toast
  onClose: () => void
}

export function Toast({ toast, onClose }: ToastProps) {
  const progressRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    if (!progressRef.current) return
    // 启动进度条动画,使用当前 Toast 的 duration
    progressRef.current.style.transition = `width ${toast.duration}ms linear`
    progressRef.current.style.width = '0%'
  }, [toast.id, toast.duration])

  return (
    <div className="group relative flex w-full items-center justify-between gap-2 rounded-md bg-slate-800 px-4 py-3 text-white">
      <div className="flex items-center gap-2">
        <span className="font-medium">{toast.title}</span>
        {toast.description && <span className="text-sm text-slate-300">{toast.description}</span>}
      </div>
      <button onClick={onClose} className="text-slate-400 hover:text-white">
        ×
      </button>
      {/* 进度条 */}
      <div
        ref={progressRef}
        className="absolute bottom-0 left-0 h-0.5 bg-white/50"
        style={{ width: '100%', transformOrigin: 'left' }}
      />
    </div>
  )
}

(3)调用时传入自定义 duration

确保调用 Toast 时正确传递参数:

// 示例调用
import { useToast } from '@/components/ui/use-toast'

function Demo() {
  const { toast } = useToast()

  const handleShowToast = () => {
    toast({
      title: '操作成功',
      description: '内容已保存',
      duration: 3000 // 自定义3秒时长
    })
  }

  return <button onClick={handleShowToast}>显示Toast</button>
}

3. 验证修复

  • 本地开发环境测试不同 duration 值,确认进度条动画时长与 Toast 消失时长一致
  • 生产环境构建后验证,确保自定义时长逻辑正常生效

内容的提问来源于stack exchange,提问作者Samuel Amann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 13:35:08