antd - 表单输入动态验证
antd - Form input dynamic validation
在我的项目中,我在登录界面使用antd Form
。如果用户没有提供电子邮件或者如果电子邮件无效,我将使用 antd 的 Form.Item
支持的 rules
属性来处理。
这是我想要实现的目标:
我还想处理另一个错误 'No account associated with email'。用户点击登录按钮后,有一个后端API调用。当后端 returns 在响应中出现此错误时,UI 应在电子邮件输入下显示此错误消息。
为此,我将此错误消息存储在状态变量 'emailError'
中,并在 Form.Item
的 'rules'
属性中使用它,如下所示:
function Login() {
const [loginForm] = Form.useForm();
const [emailError, setEmailError] = useState({ enable: false, helpText: "" });
const emailErrorRef = useRef(emailError);
const onLoginFormSubmit = async (values) => {
try {
let response = await loginRequest(values);
console.log("Login -> onLoginFormSubmit -> response", response);
// ...some logic
} catch (err) {
/*
err.response.data = {
code: 'ERR_LOGIN_NO_ACCOUNT_WITH_EMAIL',
detail: 'No account associated with this email'
}
*/
let errCode = err.response.data.code;
let errMessage = err.response.data.detail;
// If the API fails with the below error, then update the state variable.
if (errCode === "ERR_LOGIN_NO_ACCOUNT_WITH_EMAIL") {
console.log(
"Login -> update emailError -> ERR_LOGIN_NO_ACCOUNT_WITH_EMAIL"
);
setEmailError({
enable: true,
helpText: errMessage
});
}
}
};
useEffect(() => {
console.log("Login -> updated emailError", emailError);
emailErrorRef.current = emailError;
}, [emailError]);
return (
<div
style={{
position: "fixed",
width: 400,
height: 200,
top: "calc(50% - 100px)",
left: "calc(50% - 200px)"
}}
>
<Form form={loginForm} onFinish={onLoginFormSubmit}>
<Form.Item
name="email"
rules={[
{
type: "email",
message: "Please provide a valid email!"
},
{ required: true, message: "Please provide your email!" },
() => ({
validator() {
console.log(
"Inside email validator! -> emailError",
emailError
);
if (emailError.enable) {
return Promise.reject(emailError.helpText);
}
return Promise.resolve();
}
})
]}
>
<Input autoFocus placeholder="Email" prefix={<EmailIcon />} />
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true, message: "Please provide your password!" }]}
>
<Input.Password placeholder="Password" prefix={<PasswordIcon />} />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Login
</Button>
</Form.Item>
</Form>
</div>
);
}
根据我对日志的理解,我认为当我在收到来自异步 API 调用的响应后更新状态变量 'emailError'
时,表单没有被重新呈现.
更新: 我还在 HTML 中记录了状态变量 'emailError'
。变化是状态变量反映在 UI 中。所以,我认为重新渲染工作正常。但是,在重新渲染期间,rules
没有被验证..
我曾尝试在 validator()
中使用 'emailErrorRef.current'
而不是 'emailError'
但这没有用。
我在这里错过了什么?请帮忙解决这个问题!
这是一个复制这个的codesandbox:
当您对其中一个字段应用更改以及提交表单时,您的验证会调用,因此当您调用 api 并收到错误时,您的验证将在应用之前调用更改表单或再次提交,解决方案可能是通过在 antd 表单上使用 validateFields
以编程方式调用验证。像这样:
useEffect(() => {
if(emailError.enable){
loginForm.validateFields();
}
}, [emailError]);
...
<Form form={loginForm}
onChange={()=> {
if(emailError.enable)
setEmailError({enable:false, helpText:''})
}}
...></Form>
完整示例如下:
在我的项目中,我在登录界面使用antd Form
。如果用户没有提供电子邮件或者如果电子邮件无效,我将使用 antd 的 Form.Item
支持的 rules
属性来处理。
这是我想要实现的目标:
我还想处理另一个错误 'No account associated with email'。用户点击登录按钮后,有一个后端API调用。当后端 returns 在响应中出现此错误时,UI 应在电子邮件输入下显示此错误消息。
为此,我将此错误消息存储在状态变量 'emailError'
中,并在 Form.Item
的 'rules'
属性中使用它,如下所示:
function Login() {
const [loginForm] = Form.useForm();
const [emailError, setEmailError] = useState({ enable: false, helpText: "" });
const emailErrorRef = useRef(emailError);
const onLoginFormSubmit = async (values) => {
try {
let response = await loginRequest(values);
console.log("Login -> onLoginFormSubmit -> response", response);
// ...some logic
} catch (err) {
/*
err.response.data = {
code: 'ERR_LOGIN_NO_ACCOUNT_WITH_EMAIL',
detail: 'No account associated with this email'
}
*/
let errCode = err.response.data.code;
let errMessage = err.response.data.detail;
// If the API fails with the below error, then update the state variable.
if (errCode === "ERR_LOGIN_NO_ACCOUNT_WITH_EMAIL") {
console.log(
"Login -> update emailError -> ERR_LOGIN_NO_ACCOUNT_WITH_EMAIL"
);
setEmailError({
enable: true,
helpText: errMessage
});
}
}
};
useEffect(() => {
console.log("Login -> updated emailError", emailError);
emailErrorRef.current = emailError;
}, [emailError]);
return (
<div
style={{
position: "fixed",
width: 400,
height: 200,
top: "calc(50% - 100px)",
left: "calc(50% - 200px)"
}}
>
<Form form={loginForm} onFinish={onLoginFormSubmit}>
<Form.Item
name="email"
rules={[
{
type: "email",
message: "Please provide a valid email!"
},
{ required: true, message: "Please provide your email!" },
() => ({
validator() {
console.log(
"Inside email validator! -> emailError",
emailError
);
if (emailError.enable) {
return Promise.reject(emailError.helpText);
}
return Promise.resolve();
}
})
]}
>
<Input autoFocus placeholder="Email" prefix={<EmailIcon />} />
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true, message: "Please provide your password!" }]}
>
<Input.Password placeholder="Password" prefix={<PasswordIcon />} />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Login
</Button>
</Form.Item>
</Form>
</div>
);
}
根据我对日志的理解,我认为当我在收到来自异步 API 调用的响应后更新状态变量 'emailError'
时,表单没有被重新呈现.
更新: 我还在 HTML 中记录了状态变量 'emailError'
。变化是状态变量反映在 UI 中。所以,我认为重新渲染工作正常。但是,在重新渲染期间,rules
没有被验证..
我曾尝试在 validator()
中使用 'emailErrorRef.current'
而不是 'emailError'
但这没有用。
我在这里错过了什么?请帮忙解决这个问题!
这是一个复制这个的codesandbox:
当您对其中一个字段应用更改以及提交表单时,您的验证会调用,因此当您调用 api 并收到错误时,您的验证将在应用之前调用更改表单或再次提交,解决方案可能是通过在 antd 表单上使用 validateFields
以编程方式调用验证。像这样:
useEffect(() => {
if(emailError.enable){
loginForm.validateFields();
}
}, [emailError]);
...
<Form form={loginForm}
onChange={()=> {
if(emailError.enable)
setEmailError({enable:false, helpText:''})
}}
...></Form>
完整示例如下: