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

Shadcn UI Alert Dialog点击下拉菜单触发器后自动关闭问题求助

问题原因与解决方案

问题出在DropdownMenuItem的默认行为:点击菜单项时,DropdownMenu会自动关闭,而你的<DeleteAlertDialog />嵌套在<DropdownMenuContent />内部,菜单关闭会直接导致弹窗所在的DOM被隐藏/卸载,所以弹窗刚显示就消失了。

两种可行解决方法


方法一:阻止菜单项触发菜单关闭(推荐,基于Radix UI原生属性)

修改DeleteAlertDialog组件里的<DropdownMenuItem>,添加preventClose={true}属性,阻止点击时关闭菜单,同时在弹窗操作完成后手动关闭菜单:

export function DeleteAlertDialog({ entry }: { entry: Entry }) {
    const router = useRouter();
    const { close } = useDropdownMenuContext();

    return (
      <AlertDialog>
        <AlertDialogTrigger>
          {/* 添加preventClose,阻止点击时关闭菜单 */}
          <DropdownMenuItem preventClose={true}>
            Delete
          </DropdownMenuItem>
        </AlertDialogTrigger>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>确定要删除吗?</AlertDialogTitle>
            <AlertDialogDescription>
              此操作不可撤销,将永久删除服务器上的对应数据。
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel onClick={close}>Cancel</AlertDialogCancel>
            <AlertDialogAction
              onClick={async() => {
                await deleteEntry(entry);
                router.refresh();
                close(); // 删除完成后关闭菜单
              }}
            >
              Delete
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    )
  }

方法二:将弹窗移到下拉菜单外部,用状态控制显示

把弹窗组件从下拉菜单内容区移出,通过状态变量单独控制弹窗的显示/隐藏:

  1. 修改下拉菜单代码,添加状态控制逻辑:
import { useState } from 'react';

// ...其他代码
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
const [selectedEntry, setSelectedEntry] = useState<Entry | null>(null);

// ...

return (
  <>
    <DropdownMenu>
      <DropdownMenuTrigger>
        <Button variant="ghost" className="h-8 w-8 p-0">
          <span className="sr-only">打开菜单</span>
          <MoreHorizontal className="h-4 w-4" />
        </Button>
      </DropdownMenuTrigger>
      <DropdownMenuContent align="end">
        {/* ...其他菜单项 */}
        <DropdownMenuItem 
          onClick={() => {
            setSelectedEntry(entry);
            setShowDeleteDialog(true);
          }}
        >
          Delete
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
    {/* 弹窗移到下拉菜单外部 */}
    {showDeleteDialog && selectedEntry && (
      <DeleteAlertDialog 
        entry={selectedEntry} 
        onClose={() => setShowDeleteDialog(false)}
      />
    )}
  </>
)
  1. 修改DeleteAlertDialog组件,接收关闭回调:
export function DeleteAlertDialog({ entry, onClose }: { entry: Entry; onClose: () => void }) {
    const router = useRouter();

    return (
      <AlertDialog open={true} onOpenChange={onClose}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>确定要删除吗?</AlertDialogTitle>
            <AlertDialogDescription>
              此操作不可撤销,将永久删除服务器上的对应数据。
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel onClick={onClose}>Cancel</AlertDialogCancel>
            <AlertDialogAction
              onClick={async() => {
                await deleteEntry(entry);
                router.refresh();
                onClose();
              }}
            >
              Delete
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    )
  }

问题本质

你使用的Radix UI组件库中,<DropdownMenuItem>默认绑定了关闭菜单的逻辑,点击后会触发<DropdownMenuContent>的隐藏。弹窗嵌套在菜单内容区内部,菜单一关闭,弹窗所在的DOM容器就被移除,导致弹窗刚渲染就被销毁,所以只显示一瞬间。

内容的提问来源于stack exchange,提问作者Hessel van Bakel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 18:22:48