我一直在尝试为我的 React 应用程序提交表单实现 react-simple-captcha,该表单嵌套在特定页面的 MUI 对话框组件内。在验证码元素未嵌套在对话框组件内的其他页面上,它可以正常工作。但是,对于验证码嵌套在 Dialog 元素内的特定页面,页面变为空白并且控制台返回错误:
Uncaught TypeError: Cannot read properties of null (reading 'getContext') at loadCaptchaEnginge
对话框组件代码如下所示:
import { useEffect, useState } from "react";
import { loadCaptchaEnginge, LoadCanvasTemplateNoReload, validateCaptcha } from "react-simple-captcha";
import Dialog from "@mui/material/Dialog";
import IconButton from "@mui/material/IconButton";
import RefreshIcon from "@mui/icons-material/Refresh";
// some other imports
const FormDialog = ({ open, setOpen }) => {
//some states & variables declarations
const handleSubmit = () => {
//form submit event function
}
useEffect(() => {
loadCaptchaEnginge(6, "#13baba", "#f5f5f5");
}, []);
return (
<Dialog open={open} onClose={() => setOpen(false)}>
<form onSubmit={handleSubmit}>
{/* other elements */}
<LoadCanvasTemplateNoReload />
<IconButton
aria-label="Reload Captcha"
size="small"
color="primary"
onClick={() => loadCaptchaEnginge(6, "#13baba", "whitesmoke");}}
>
<RefreshIcon />
</IconButton>
</form>
</Dialog>
)
}
问题是,如果我注释掉调用
useEffect
函数的 loadCaptchaEnginge()
钩子,则页面加载成功,并且 IconButton
在单击时正常调用 loadCaptchaEnginge()
,并且验证码画布元素成功重新加载。
对于上下文,以下是包含调用 FormDialog 组件的按钮的父组件代码:
import { useState } from "react";
import FormDialog from "./FormDialog";
import Button from "@mui/material/Button"
// some other imports
const PageLayout = () => {
const [dialogOpen, setDialogOpen] = useState(false);
return (
<>
{/* some other elements */}
<Button
variant="contained"
onClick={() => setDialogOpen(true)}
>
Apply Now
</Button>
<FormDialog
open={dialogOpen}
setOpen={setDialogOpen}
/>
</>
)
}
经过一番搜索,我尝试使用
useRef
hook 创建对 FormDialog 元素的引用并修改 useEffect
部分,使 FormDialog 变成这样:
const captchaRef = useRef(null);
useEffect(() => {
const captchaEl = captchaRef.current;
if (captchaEl) {
loadCaptchaEnginge(6, "#13baba", "#f5f5f5");
}
}, []);
return (
<Dialog open={open} onClose={() => setOpen(false)} ref={captchaRef}>
{/* rest of the code */}
<Dialog>
)
实现此操作后,页面不再为空白,但在 FormDialog 出现后,验证码画布仍然未呈现。只有单击验证码重新加载按钮后,验证码画布才会出现。
我遇到了同样的问题:MUI 对话框元素内的画布元素。 通过创建一个单独的 Canvas 组件来解决这个问题:
function Canvas({frequency, amplitude, phase}) {
const canvasRef = useRef(null)
useEffect(() => {
const canvas = canvasRef.current
const ctx = canvas.getContext("2d")
{/* ... */}
}, [frequency, amplitude, phase])
return (
<canvas ref={canvasRef} width={300} height={150}/>
)
}
...并在返回语句中调用该组件并传递所需的道具:
<Dialog>
<DialogContent>
<Canvas
props={sliderOneValue}
amplitude={sliderTwoValue}
phase={sliderThreeValue}
/>
{/* ... */}
</DialogContent>
</Dialog>