【问题标题】:While doing form validation on submit a form, the component is not updating in React在提交表单时进行表单验证时,组件没有在 React 中更新
【发布时间】:2020-09-20 14:05:32
【问题描述】:

我在 react 中登录,

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】:

我将您的代码放在code sandbox 中,它似乎工作得很好。请注意,我删除了 className 属性并评论了测试您的问题所不需要的内容,例如 redux 导入。

由于我删除了className 属性,这可能是CSS 问题,您的错误span 实际呈现但不可见(查看浏览器的开发工具以查看span 是否真的存在不存在)。

此外,如果您使用大量表单,我建议您使用库,因为状态处理 + 验证可能会变得相当复杂,并且有很多解决方案。
我编写了自己的库 - react-fluent-form - 随时查看。

编辑

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

// 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 将假定没有发生任何变化,因此会导致bail out of a state update。如果您在 state 中使用复杂类型(如对象或数组),您总是需要创建一个新的引用,而不是调整之前的引用:

// 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);

编辑 2

我为validate 添加了一个返回值,以便在调用validateForm 时使用更新后的validationError 对象。

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

    // ...

    return validationError;
};

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

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

请参阅updated code sandbox

【讨论】:

  • 当我尝试提交而不更改字段时,它不起作用。
  • @LakshmipriyaMukundan 抱歉,我完全忽略了那部分。我更新了我的答案
  • 现在的问题是错误变量没有更新,'validationError' 有正确的值。但我认为 setError 无法正常工作。
  • @LakshmipriyaMukundan 我添加了一个带有工作代码的新代码沙箱。希望对你有帮助
猜你喜欢
  • 2014-07-28
  • 1970-01-01
  • 2020-09-22
  • 2012-11-20
  • 2019-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-21
相关资源
最近更新 更多