简体   繁体   English

Formik 和 yup 验证不适用于所需

[英]Formik and yup validation not working for required

I use Formik and Yup to validate my login form in React.我使用 Formik 和 Yup 在 React 中验证我的登录表单。 As you can see from the code below, I check that the inputs are not empty and then call my backend to check if the user exists.从下面的代码中可以看到,我检查输入是否为空,然后调用我的后端来检查用户是否存在。 The call to the backend works, because if the user does not exist I report the error in the div with id "invalidUser" (I do not know if this is the most correct solution, I thought of a way to insert the error in the form of control of formik but I have not succeeded) while the required() Yup doesn't work because it doesn't report errors when I don't write anything in the inputs.对后端的调用有效,因为如果用户不存在,我会在id为“invalidUser”的div中报告错误(我不知道这是否是最正确的解决方案,我想了一种方法将错误插入到formik 的控制形式,但我没有成功)而 required() Yup 不起作用,因为当我没有在输入中写任何内容时它不会报告错误。 Why?为什么? Do you have a solution?你有解决方案吗? Also my control solution if the user exists or not can go well or there is a better one?如果用户存在与否,我的控制解决方案也可以 go 好还是有更好的解决方案?

index.js: 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} alt="icon" />
                <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: 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;
    }
`

you should avoid to access directly the DOM when using React so you should save the invalidUser information inside a state and then show/hide the ErrorMessage depending on that.您应该避免在使用 React 时直接访问 DOM,因此您应该将invalidUser信息保存在 state 中,然后根据该信息显示/隐藏ErrorMessage

You could also do the validation of the user directly before the actual submit.您也可以在实际提交之前直接对用户进行验证。

So you could do something like the following:因此,您可以执行以下操作:

 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} alt="icon" /> <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

Of course consider the above code just like an hint in order to start to find the best solution for yourself.当然,将上述代码视为提示,以便开始为自己找到最佳解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM