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> ) }
方法二:将弹窗移到下拉菜单外部,用状态控制显示
把弹窗组件从下拉菜单内容区移出,通过状态变量单独控制弹窗的显示/隐藏:
- 修改下拉菜单代码,添加状态控制逻辑:
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)} /> )} </> )
- 修改
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
相关产品推荐
相关产品推荐

