React 中处理警告对话框的最简洁方法🥰
阅读时间——5分钟☕️
大家好!我是个懒惰的开发者,今天我们来聊聊如何在 React 中轻松处理对话框提示😢。如果你已经厌倦了为了创建一个该死的“一个问题”模态对话框而进行大量的复制粘贴——那就准备好咖啡,我们开始吧。
目标
我们想找到一种最简洁的提示框显示方案,类似于浏览器自带的提示alert框功能。
const isConfirmed = alert("Are you sure you want to remove this burrito?");
if (isConfirmed) {
await api.deleteThisAwfulBurrito();
}
抢先看
最终我们会得到类似这样的结果。
const YourAwesomeComponent = () => {
const confirm = useConfirmation()
confirm({
variant: "danger",
title: "Are you sure you want to remove this burrito?",
description: "If you will remove this burrito you will regret it 😡!!"
}).then(() => {
api.deleteThisAwfulBurrito();
});
}
有兴趣吗?我们来写点代码吧。
首先,我们需要从创建模态对话框开始。这是一个用❤️和material-ui构建的简单警告对话框。
import {
Button,
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
DialogActions,
} from "@material-ui/core";
export const ConfirmationDialog = ({
open,
title,
variant,
description,
onSubmit,
onClose
}) => {
return (
<Dialog open={open}>
<DialogTitle>{title}</DialogTitle>
<DialogContent>
<DialogContentText>{description}</DialogContentText>
</DialogContent>
<DialogActions>
<Button color="primary" onClick={onSubmit}>
YES, I AGREE
</Button>
<Button color="primary" onClick={onClose} autoFocus>
CANCEL
</Button>
</DialogActions>
</Dialog>
);
};
好的,但是我们要如何让它动态运行呢?这是一个值得思考的问题。如果用户一次只能看到一个提示对话框,为什么每个组件都需要那么多对话框呢?
好了,我们开始吧。我们只需要在应用程序根目录渲染一个顶级模态框,并在需要时显示它。我们将利用 React Hooks 的强大功能,让它看起来更加优雅。
包裹上下文
让我们创建一个新的上下文实例,并将组件树包裹在其中。此外,创建一个简单的状态,用于保存当前显示的警报选项(例如标题、描述以及您需要的所有内容)。
interface ConfirmationOptions {
title: string;
description: string;
}
const ConfirmationServiceContext = React.createContext<
// we will pass the openning dialog function directly to consumers
(options: ConfirmationOptions) => Promise<void>
>(Promise.reject);
export const ConfirmationServiceProvider= ({ children }) => {
const [
confirmationState,
setConfirmationState
] = React.useState<ConfirmationOptions | null>(null);
const openConfirmation = (options: ConfirmationOptions) => {
setConfirmationState(options);
return Promise.resolve()
};
return (
<>
<ConfirmationServiceContext.Provider
value={openConfirmation}
children={children}
/>
<Dialog open={Boolean(confirmationState)} {...confirmationState} />
</>
);
};
现在,只要我们连接任何消费者并调用提供的函数,我们的对话框就会打开。
解决确认
现在我们需要处理对话框关闭和接收用户回调的问题。这里使用了Promise基于 API 的方法,但也可以使用回调的方式实现。在这个例子中,一旦用户接受或取消了提示框,等待的 Promise 就会被解析或拒绝。
为此,我们需要保存Promise解析函数,并在适当的用户操作时调用它们。React 的 `resolve` 类ref是最佳选择。
const awaitingPromiseRef = React.useRef<{
resolve: () => void;
reject: () => void;
}>();
const openConfirmation = (options: ConfirmationOptions) => {
setConfirmationState(options);
return new Promise((resolve, reject) => {
// save the promise result to the ref
awaitingPromiseRef.current = { resolve, reject };
});
};
const handleClose = () => {
// Mostly always you don't need to handle canceling of alert dialog
// So shutting up the unhandledPromiseRejection errors
if (confirmationState.catchOnCancel && awaitingPromiseRef.current) {
awaitingPromiseRef.current.reject();
}
setConfirmationState(null);
};
const handleSubmit = () => {
if (awaitingPromiseRef.current) {
awaitingPromiseRef.current.resolve();
}
setConfirmationState(null);
};
好了!我们的对话机器就快完成了!还剩最后一件事——创建一个自定义钩子以提高可读性。
export const useConfirmationService = () =>
React.useContext(ConfirmationServiceContext);
定制
您可以通过传递额外的variant属性轻松自定义对话框内容。只需将其添加到……ConfirmationOptions
export interface ConfirmationOptions {
variant: "danger" | "info";
title: string;
description: string;
}
您可以根据需要渲染不同的对话框内容。
<DialogActions>
{variant === "danger" && (
<>
<Button color="primary" onClick={onSubmit}>
Yes, I agree
</Button>
<Button color="primary" onClick={onClose} autoFocus>
CANCEL
</Button>
</>
)}
<span class="si">{</span><span class="nx">variant</span> <span class="o">===</span> <span class="dl">"</span><span class="s2">info</span><span class="dl">"</span> <span class="o">&&</span> <span class="p">(</span>
<span class="p"><</span><span class="nc">Button</span> <span class="na">color</span><span class="p">=</span><span class="s">"primary"</span> <span class="na">onClick</span><span class="p">=</span><span class="si">{</span><span class="nx">onSubmit</span><span class="si">}</span><span class="p">></span>
OK
<span class="p"></</span><span class="nc">Button</span><span class="p">></span>
<span class="p">)</span><span class="si">}</span>
</DialogActions>
准备好了吗?!
这是最终的可运行示例。如果你愿意,可以直接借鉴文件的实现ConfirmationService.tsx。这部分逻辑与我们讨论的内容相当独立。
文章来源:https://dev.to/dmtrkovalenko/the-neatest-way-to-handle-alert-dialogs-in-react-1aoePS:本文撰写过程中没有墨西哥卷饼受到伤害

