我正在尝试创建一个对话框上下文以允许可重用的对话框。我还尝试让它在关闭时返回一个值,以将该数据传递给需要它的组件。
这是 DialogContext 的相关部分:
...
const defaultValue: DialogParams = { open: false, children: null };
export default function DialogProvider({ children }) {
const [dialog, setDialog] = useState<DialogParams>(defaultValue);
const [resolver, setResolver] = useState<((value: any) => void) | null>(null);
const theme = useTheme();
const fullscreen = useMediaQuery(theme.breakpoints.down('md'));
function openDialog(options: Omit<DialogParams, "open">): Promise<any> {
setDialog({ ...options, open: true });
return new Promise((resolve: (value: any) => void) => {
setResolver(() => resolve);
});
}
const closeDialog: DialogReturnProps = (props?: any) => {
if (resolver) {
resolver(props);
}
setResolver(null);
setDialog(defaultValue);
}
const dialogContextObj: DialogState = [openDialog, closeDialog];
return <DialogContext.Provider value={dialogContextObj}>
{children}
{
<Dialog fullScreen={fullscreen} open={dialog.open} onClose={() => closeDialog()}>
{
<div className="grid"><IconButton className="justify-self-end" onClick={() => closeDialog()}><Close color="error" /></IconButton></div>
}
{dialog.children}
</Dialog>
}
</DialogContext.Provider>
}
这是我目前的使用方式:
const addPlayerDialogRef = useRef(AddPlayerDialog);
const [openDialog, closeDialog] = useDialog();
...
const val = await openDialog({
children: <AddPlayerDialog handleSubmit={closeDialog} ref={addPlayerDialogRef} />
});
console.log("HERE", val);
if (val) {
await playerCtx.addPlayers([val]);
await refresh();
}
...
还有addPlayerDialog:
const AddPlayerDialog = forwardRef<any, { handleSubmit: DialogReturnProps }>(function AddPlayerDialog(props, _) {
const { handleSubmit } = props;
...
function addPlayer(ev: FormEvent<HTMLFormElement>) {
ev.preventDefault();
const data = new FormData(ev.target as HTMLFormElement)
if (data.get("firstName") && data.get('lastName') && data.get('gender')) {
const player: Player = {
firstName: data.get('firstName')! as string,
lastName: data.get('lastName')! as string,
rating: data.get('rating') ? parseInt(data.get('rating')!.toString()) : 0
};
handleSubmit(player);
}
}
基本上,我处理 AddPlayerDialog 中的所有验证,当需要关闭对话框时,我调用handleSubmit 函数(应该是 closeDialog 函数),这应该解决承诺。然而,我遇到的问题是,一半的时间它工作正常,而另一半的时间解析器为空。我不太确定为什么它会为空,尤其是当我们在 openDialog 函数中设置它时。当我尝试单击对话框上的“x”按钮关闭而不发送值,然后重新打开它并尝试填写表单并提交时,我总是可以打破它。
Roar S.的回答解决了我的问题。我从 useState 更改为 useRef,这使得它可以工作。我不是 100% 确定为什么它之前不起作用,但这确实有效。
这是我所做的更改:
在我更改的对话框上下文中:
const [resolver, setResolver] = useState<((value: any) => void) | null>(null);
到
let resolver = useRef<((value: any) => void) | null>(null);
打电话/更新时我做了:
resolver.current(props);
和
return new Promise((resolve: (value: any) => void) => {
resolver.current = resolve;
});