如何等待AlertDialog用户选择?Chakra UI+Recoil实现遇阻
解决Chakra UI AlertDialog无法等待用户选择的问题
你的核心问题在于:调用openAlert()后立即同步判断状态,此时用户还未与弹窗交互,状态不会发生变化,导致逻辑直接执行而非等待用户选择。以下是两种可行的解决方案:
方案一:通过回调函数传递操作逻辑(推荐)
这种方式无需依赖全局状态,直接将父组件的操作逻辑通过props传递给弹窗组件,用户点击对应按钮时触发回调,完全符合异步交互的逻辑。
修改弹窗组件(AlertDelCreateCancel)
import { AlertDialog, AlertDialogBody, AlertDialogContent, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, Button, } from "@chakra-ui/react" export function AlertDelCreateCancel({ isOpen, onClose, onCancel, onDelete, onCreateEmpty }) { // 取消操作 const handleCancel = () => { onCancel?.() onClose() } // 删除操作 const handleDelete = () => { onDelete?.() onClose() } // 创建空标签操作 const handleCreateEmpty = () => { onCreateEmpty?.() onClose() } return ( <AlertDialog isOpen={isOpen} onClose={handleCancel} // 点击弹窗自带关闭按钮也触发取消逻辑 closeOnOverlayClick={false} > <AlertDialogOverlay> <AlertDialogContent backgroundColor="dark.background"> <AlertDialogHeader fontSize="lg" fontWeight="bold"> Your Region </AlertDialogHeader> <AlertDialogBody> Are you sure you want to exit....? </AlertDialogBody> <AlertDialogFooter> <Button onClick={handleCancel}>Cancel</Button> <Button colorScheme="red" onClick={handleDelete} ml={3}> Delete </Button> <Button colorScheme="red" onClick={handleCreateEmpty} ml={3}> Create Empty </Button> </AlertDialogFooter> </AlertDialogContent> </AlertDialogOverlay> </AlertDialog> ) }
修改父组件调用代码
import { useDisclosure } from "@chakra-ui/react" import { AlertDelCreateCancel } from "./path-to-your-component" // ...其他状态和逻辑定义 const { isOpen: isAlertOpen, onOpen: openAlert, onClose: closeAlert, } = useDisclosure() // 定义各个操作的具体逻辑 const handleCancel = () => { // 取消后的逻辑,比如无操作或重置状态 } const handleDelete = () => { // 执行删除标签逻辑 setTags((prev) => prev.filter((s) => s.id !== tagSelected.id)) } const handleCreateEmpty = () => { // 执行创建空标签逻辑,示例:添加一个空标签到列表 setTags((prev) => [...prev, { id: Date.now(), name: "" }]) } // 触发弹窗的示例(比如绑定到某个按钮点击) // <Button onClick={openAlert}>打开操作弹窗</Button> return ( <> {/* 其他组件内容 */} <AlertDelCreateCancel isOpen={isAlertOpen} onClose={closeAlert} onCancel={handleCancel} onDelete={handleDelete} onCreateEmpty={handleCreateEmpty} /> </> )
方案二:通过Recoil状态监听实现(依赖全局状态)
如果你坚持使用Recoil状态传递结果,需要通过useEffect监听状态变化,而非在打开弹窗后立即判断:
完善弹窗组件的状态设置
import { AlertDialog, AlertDialogBody, AlertDialogContent, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, Button, } from "@chakra-ui/react" import { useRecoilState } from "recoil" import { unTitleTag as unTitleTagAtom } from "../../atoms/controls" export function AlertDelCreateCancel({ isOpen, onClose }) { const [unTitletag, setunTitleTag] = useRecoilState(unTitleTagAtom) const cancelAnswer = () => { setunTitleTag(1) onClose() } const deleteTag = () => { setunTitleTag(2) onClose() } const createEmptyTag = () => { setunTitleTag(3) onClose() } return ( <AlertDialog isOpen={isOpen} onClose={cancelAnswer} closeOnOverlayClick={false} > <AlertDialogOverlay> <AlertDialogContent backgroundColor="dark.background"> <AlertDialogHeader fontSize="lg" fontWeight="bold"> Your Region </AlertDialogHeader> <AlertDialogBody> Are you sure you want to exit....? </AlertDialogBody> <AlertDialogFooter> <Button onClick={cancelAnswer}>Cancel</Button> <Button colorScheme="red" onClick={deleteTag} ml={3}> Delete </Button> <Button colorScheme="red" onClick={createEmptyTag} ml={3}> Create Empty </Button> </AlertDialogFooter> </AlertDialogContent> </AlertDialogOverlay> </AlertDialog> ) }
父组件中监听状态变化
import { useEffect } from "react" import { useDisclosure } from "@chakra-ui/react" import { useRecoilState } from "recoil" import { unTitleTag as unTitleTagAtom } from "../../atoms/controls" import { AlertDelCreateCancel } from "./path-to-your-component" // ...其他状态定义 const { isOpen: isAlertOpen, onOpen: openAlert, onClose: closeAlert, } = useDisclosure() const [unTitletag, setunTitleTag] = useRecoilState(unTitleTagAtom) // 监听状态变化,执行对应逻辑 useEffect(() => { if (unTitletag === 1) { // 取消操作逻辑 } else if (unTitletag === 2) { // 删除标签逻辑 setTags((prev) => prev.filter((s) => s.id !== tagSelected.id)) } else if (unTitletag === 3) { // 创建空标签逻辑 } // 执行后重置状态,避免重复触发 if (unTitletag !== 0) { // 假设初始值为0 setunTitleTag(0) } }, [unTitletag, setTags, tagSelected.id, setunTitleTag]) // 触发弹窗只需调用openAlert(),无需后续同步判断 // <Button onClick={openAlert}>打开弹窗</Button> return ( <> {/* 其他组件内容 */} <AlertDelCreateCancel onClose={closeAlert} isOpen={isAlertOpen} /> </> )
为什么原代码无效?
openAlert()是同步执行的方法,仅负责打开弹窗,不会阻塞后续代码执行。你在调用后立即判断unTitleTag,此时用户还未点击任何按钮,状态仍为初始值,导致逻辑无法按预期等待用户选择。
内容的提问来源于stack exchange,提问作者Eli7
相关产品推荐
相关产品推荐

