Formik 和 yup 验证不适用于所需
Posted
技术标签:
【中文标题】Formik 和 yup 验证不适用于所需【英文标题】:Formik and yup validation not working for required 【发布时间】:2022-01-17 22:23:51 【问题描述】:我使用 Formik 和 Yup 在 React 中验证我的登录表单。正如您从下面的代码中看到的那样,我检查输入是否为空,然后调用我的后端来检查用户是否存在。对后端的调用有效,因为如果用户不存在,我会在id为“invalidUser”的div中报告错误(我不知道这是否是最正确的解决方案,我想了一种方法将错误插入到formik 的控制形式,但我没有成功)而 required() Yup 不起作用,因为当我不在输入中写任何内容时它不会报告错误。为什么?你有解决方案吗?如果用户存在与否,我的控制解决方案也可以顺利进行还是有更好的解决方案?
index.js:
import React from 'react'
import useNavigate from "react-router-dom";
import Form, Button from 'react-bootstrap';
import LoginWrapper, LoginForm, IconImg, SocialLogin, ErrorMessage from './AccessoElements';
import GoogleLogin from 'react-google-login';
import GoogleButton from 'react-google-button';
import $ from 'jquery';
import FacebookLogin from 'react-facebook-login';
import FaFacebookF from 'react-icons/fa';
import Formik from 'formik';
import * as yup from 'yup';
const responseGoogle = (response) =>
console.log(response);
console.log(response.profileObj);
const responseFacebook = (response) =>
console.log(response);
console.log(response.profileObj);
const Accesso = () =>
const schemaLogin = yup.object().shape(
username: yup.string().required("L'username o l'email è obbligatorio."),
password: yup.string().required('La password è obbligatoria.'),
).test(
name: "invalidUser",
test: async (values) =>
const requestOptions =
method: 'POST',
headers: 'Content-Type': 'application/json' ,
body: JSON.stringify(
"username": values.username,
"password": values.password
)
;
let response = await fetch("http://localhost:8080/api/v1/auth/signin/available", requestOptions)
if (response.ok)
$("#invalidUser").css("display", "none");
return true;
else
$("#invalidUser").css("display", "flex");
return this.createError(
message: "Email/Username or password invalid.",
)
)
const navigate = useNavigate();
return (
<LoginWrapper>
<LoginForm>
<IconImg src=require('../../../images/avatarUser.png').default />
<Formik
validationSchema=schemaLogin
validateOnChange=false
validateOnBlur=false
onSubmit=(values) =>
const requestOptions =
method: 'POST',
headers: 'Content-Type': 'application/json' ,
body: JSON.stringify("username": values.username, "password": values.password)
;
fetch("http://localhost:8080/api/v1/auth/signin", requestOptions)
.then(response => response.json())
.then(data =>
sessionStorage.setItem("username", data['username']);
sessionStorage.setItem("email", data['email']);
sessionStorage.setItem("roles", data['roles']);
sessionStorage.setItem("isLoggedIn", true);
sessionStorage.setItem("tokenType", data['tokenType']);
sessionStorage.setItem("accessToken", data['accessToken']);
navigate("/");
)
.catch(err => console.log(err))
initialValues=
username: '',
password: '',
>
(
handleSubmit,
handleChange,
values,
errors,
) => (
<Form noValidate onSubmit=handleSubmit>
<Form.Group className="position-relative mb-3" controlId="formBasicEmail">
<Form.Control
type="text"
name="username"
placeholder="Username"
value=values.username
onChange=handleChange
isInvalid=!!errors.username
/>
<Form.Control.Feedback type="invalid" tooltip>
errors.username
</Form.Control.Feedback>
</Form.Group>
<Form.Group className="position-relative mb-3" controlId="formBasicPassword">
<Form.Control
type="password"
name="password"
placeholder="Password"
value=values.password
onChange=handleChange
isInvalid=!!errors.password
/>
<Form.Control.Feedback type="invalid" tooltip>
errors.password
</Form.Control.Feedback>
</Form.Group>
<Button variant="primary w-100" type="submit">Login</Button>
</Form>
)
</Formik>
<ErrorMessage id="invalidUser">
<p>Email/Username o password invalidi.</p>
</ErrorMessage>
</LoginForm>
<div className="divider"><span></span><span>Oppure</span><span></span></div>
<SocialLogin>
<div className="container">
<FacebookLogin
appId="1156207558121098"
autoLoad=false
fields="name,email,picture"
callback=responseFacebook
textButton="Accedi con Facebook"
icon=<FaFacebookF style=marginRight: "10px", marginBottom: "3px"></FaFacebookF>
cssClass="btnFacebook"
language="it_IT"
/>
</div>
<div className="container">
<GoogleLogin
clientId="459333865802-8u7ted62or2vluagnus58250np433omm.apps.googleusercontent.com"
buttonText="Accedi con Google"
onSuccess=responseGoogle
onFailure=responseGoogle
cookiePolicy='single_host_origin'
isSignedIn=true
language="it_IT"
render=renderProps => (
<GoogleButton
onClick=renderProps.onClick
label='Accedi con Google'
style=fontWeight: "700", fontFamily: "Helvetica, sans-serif", WebkitFontSmoothing: "antialiased", justifyContent: "center", minWidth: "240px"
/>
)
/>
</div>
</SocialLogin>
</LoginWrapper>
)
export default Accesso
AccessoElements.js:
import styled from 'styled-components';
export const LoginWrapper = styled.div`
align-items: center;
min-height: 100vh;
background: #0c0c0c;
`
export const LoginForm = styled.div`
width: 25%;
margin: 0 auto;
margin-bottom: 50px;
padding-top: 140px;
text-align: center;
@media screen and (max-width: 968px)
width: 45%;
@media screen and (max-width: 768px)
width: 55%;
`
export const SocialLogin = styled.div`
display: flex;
width: 30%;
margin: 0 auto;
justify-content: center;
@media screen and (max-width: 968px)
width: 55%;
@media screen and (max-width: 600px)
flex-wrap: wrap;
`
export const IconImg = styled.img`
width: 70px;
height: 70px;
margin-bottom: 2rem;
`
export const ErrorMessage = styled.div`
display: none;
color: #dc3545;
margin-top: 1rem;
p
margin-bottom: 0rem;
`
【问题讨论】:
【参考方案1】:在使用 React 时应避免直接访问 DOM,因此应将 invalidUser
信息保存在状态中,然后根据该状态显示/隐藏 ErrorMessage
。
您也可以在实际提交之前直接对用户进行验证。
因此您可以执行以下操作:
import React from 'react'
import useNavigate from "react-router-dom";
import Form, Button from 'react-bootstrap';
import LoginWrapper, LoginForm, IconImg, SocialLogin, ErrorMessage from './AccessoElements';
import GoogleLogin from 'react-google-login';
import GoogleButton from 'react-google-button';
import $ from 'jquery';
import FacebookLogin from 'react-facebook-login';
import FaFacebookF from 'react-icons/fa';
import Formik from 'formik';
import * as yup from 'yup';
const responseGoogle = (response) =>
console.log(response);
console.log(response.profileObj);
const responseFacebook = (response) =>
console.log(response);
console.log(response.profileObj);
const Accesso = () =>
const [invalidUser, setInvalidUser] = React.useState(false)
const testUser = async (values) =>
const requestOptions =
method: 'POST',
headers: 'Content-Type': 'application/json' ,
body: JSON.stringify(
"username": values.username,
"password": values.password
)
;
let response = await fetch("http://localhost:8080/api/v1/auth/signin/available", requestOptions)
setInvalidUser(!response.ok)
return response.ok
const schemaLogin = yup.object().shape(
username: yup.string().required("L'username o l'email è obbligatorio."),
password: yup.string().required('La password è obbligatoria.'),
)
const navigate = useNavigate();
return (
<LoginWrapper>
<LoginForm>
<IconImg src=require('../../../images/avatarUser.png').default />
<Formik
validationSchema=schemaLogin
validateOnChange=false
validateOnBlur=false
onSubmit=async (values) =>
const isValid = await testUser(values)
if (isValid)
const requestOptions =
method: 'POST',
headers: 'Content-Type': 'application/json' ,
body: JSON.stringify("username": values.username, "password": values.password)
;
fetch("http://localhost:8080/api/v1/auth/signin", requestOptions)
.then(response => response.json())
.then(data =>
sessionStorage.setItem("username", data['username']);
sessionStorage.setItem("email", data['email']);
sessionStorage.setItem("roles", data['roles']);
sessionStorage.setItem("isLoggedIn", true);
sessionStorage.setItem("tokenType", data['tokenType']);
sessionStorage.setItem("accessToken", data['accessToken']);
navigate("/");
)
.catch(err => console.log(err))
initialValues=
username: '',
password: '',
>
(
handleSubmit,
handleChange,
values,
errors,
) => (
<Form noValidate onSubmit=handleSubmit>
<Form.Group className="position-relative mb-3" controlId="formBasicEmail">
<Form.Control
type="text"
name="username"
placeholder="Username"
value=values.username
onChange=handleChange
isInvalid=!!errors.username
/>
<Form.Control.Feedback type="invalid" tooltip>
errors.username
</Form.Control.Feedback>
</Form.Group>
<Form.Group className="position-relative mb-3" controlId="formBasicPassword">
<Form.Control
type="password"
name="password"
placeholder="Password"
value=values.password
onChange=handleChange
isInvalid=!!errors.password
/>
<Form.Control.Feedback type="invalid" tooltip>
errors.password
</Form.Control.Feedback>
</Form.Group>
<Button variant="primary w-100" type="submit">Login</Button>
</Form>
)
</Formik>
invalidUser && <ErrorMessage id="invalidUser">
<p>Email/Username o password invalidi.</p>
</ErrorMessage>
</LoginForm>
<div className="divider"><span></span><span>Oppure</span><span></span></div>
<SocialLogin>
<div className="container">
<FacebookLogin
appId="1156207558121098"
autoLoad=false
fields="name,email,picture"
callback=responseFacebook
textButton="Accedi con Facebook"
icon=<FaFacebookF style=marginRight: "10px", marginBottom: "3px"></FaFacebookF>
cssClass="btnFacebook"
language="it_IT"
/>
</div>
<div className="container">
<GoogleLogin
clientId="459333865802-8u7ted62or2vluagnus58250np433omm.apps.googleusercontent.com"
buttonText="Accedi con Google"
onSuccess=responseGoogle
onFailure=responseGoogle
cookiePolicy='single_host_origin'
isSignedIn=true
language="it_IT"
render=renderProps => (
<GoogleButton
onClick=renderProps.onClick
label='Accedi con Google'
style=fontWeight: "700", fontFamily: "Helvetica, sans-serif", WebkitFontSmoothing: "antialiased", justifyContent: "center", minWidth: "240px"
/>
)
/>
</div>
</SocialLogin>
</LoginWrapper>
)
export default Accesso
当然,将上述代码视为提示,以便开始为自己找到最佳解决方案。
【讨论】:
非常感谢!以上是关于Formik 和 yup 验证不适用于所需的主要内容,如果未能解决你的问题,请参考以下文章
使用 Formik 和 Yup 和 React-select 进行验证
Yup.mixed().test() 似乎破坏了 Formik 表单验证
Formik Yup `.test()` 自定义验证无法正常工作