在提交表单时进行表单验证时,组件没有在React中更新。

问题描述 投票:0回答:1

我有一个在反应中登录。

import React, { Fragment, useState } from 'react';
import { useHistory } from "react-router-dom";
import { useDispatch } from 'react-redux';
import { Link } from 'react-router-dom';

import { auth } from '../actions';


export const Login = () => {
   let history = useHistory();
   const dispatch = useDispatch();

   const [email, setEmail] = useState('');
   const [password, setPassword] = useState('');
   const [error, setError] = useState({email: '', password: ''});

   const validEmailRegex = RegExp(/^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|. 
    (\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i);

   const handleChange = e => {
      e.persist();
      const { name, value } = e.target;
      let validationError = error;

      switch(name) {
        case 'email':
            setEmail(value);
            validationError.email = validEmailRegex.test(value) ? '' : 'Email is not valid';
            break;
        case 'password':
            setPassword(value)
            validationError.password = value.length < 8 ? 'Password must be 8 characters 
            long!': '';
            break;
        case 'submit':
            validationError.email = email.length < 1 ? 'Email is required'  : '';
            validationError.password = password.length < 1 ? 'Password is required'  : '';
        default:
            break;
      };
    setError(validationError);
    console.log('in change', error)
   };

const validateForm = (errors) => {
    let valid = true;
    Object.values(errors).forEach(
      // if we have an error string set valid to false
      (val) => val.length > 0 && (valid = false)
    );
    return valid;
};

const validate = () => {
    console.log('email,password', email, password);
    let validationError = error;
    if(!email){
        validationError.email = 'Email is required';
    }
    if(!password){
        validationError.password = 'Password is required';
    }
    setError(validationError);
    console.log('in validate',error)
};

const onSubmit = e => {
    e.preventDefault();
    validate();
    console.log('error on submit', error);
    if(validateForm(error)) {
        dispatch(auth(email, password, true));
        history.replace('/home');
      }else{
        console.error('Invalid Form', error)
      }
};
return (
    <Fragment>
        <div className="w-full max-w-sm container mt-20 mx-auto">
            <form onSubmit={onSubmit}>
                <div className="w-full mb-5">
                    <label className="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" htmlFor="email">
                        Email
                    </label>
                    <input className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:text-gray-600" value={email} name='email' onChange={(e) => handleChange(e)} type="text" placeholder="Email" />
                    { error && <span style={{color: "red"}}>{error['email']}</span>}
                </div>
                <div className="w-full  mb-5">
                    <label className="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" htmlFor="password">
                        Password
                    </label>
                    <input className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:text-gray-600" value={password} name='password' onChange={(e) => handleChange(e)} type="password" placeholder="Password" />
                    { error && <span style={{color: "red"}}>{error['password']}</span>}
                </div>
                <div className="flex items-center justify-between">
                    <button className="mt-5 bg-green-400 w-full hover:bg-green-500 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
                        Login
                    </button>
                </div>
                <div className="text-center mt-4 text-gray-500"><Link to='/'>Cancel</Link></div>
            </form>
        </div>
    </Fragment>
)

}

我在onchange和submit中添加了字段验证,onchange验证工作正常,但显示错误。提交时的验证也很好,但当我尝试提交时,没有任何字段的变化,组件仍然没有显示错误。

我是新手,不知道这样做是否正确。先谢谢你了。

javascript reactjs redux react-hooks
1个回答
1
投票

我把你的代码放在了 代码沙盒 而且似乎工作得很好。请注意,我删除了 className 属性和注释的东西,是没有必要的测试你的问题,如 redux 的进口。

由于我删除了 className 属性,这可能是一个 CSS 问题,你的错误 span 实际上已被渲染,但不可见 (查看浏览器的开发工具,以查看是否有 span 是真的不存在)。)

另外,如果你使用大量的表单,我建议你使用一个库,因为状态处理+验证可能会变得相当复杂,有很多解决方案。我写了我自己的库- 反应-流形 - 请随意查看。

编辑

这里的问题是,当你更新 error 使用 setError 你总是传递相同的对象引用。

// this is not doing a copy
// validationError will have the same reference as error
let validationError = error;

// ...

// following line will not trigger a rerender
setError(validationError);

因为 errorvalidationError 有相同的参照物。react 会认为没有发生变化,因此会造成 解救. 如果你在状态下使用复杂类型(如对象或数组),你总是需要创建一个新的引用,而不是适应以前的引用。

// this is an actual copy using the spread operator
// validationError will have different reference than error
let validationError = {...error};

// ...

// triggers rerender as expected
setError(validationError);

EDIT 2

我为 validate 使用更新后的 validationError 对象时,调用 validateForm.

const validate = () => {
    //..
    let validationError = { ...error };

    // ...

    return validationError;
};

const onSubmit = e => {
    // ...
    const validationError = validate();

    if (validateForm(validationError)) {
    //...
    }
};

更新代码沙盒.

热门问题
推荐问题
最新问题