【问题标题】:React: How to change form validation from onSubmit validation for all fields, to onBlur instant validation for each field in the form?React:如何将表单验证从所有字段的 onSubmit 验证更改为表单中每个字段的 onBlur 即时验证?
【发布时间】:2021-04-01 08:22:21
【问题描述】:

我的表单运行良好,但我需要立即进行验证(一旦用户散焦该字段,我希望仅显示该字段的错误消息)。目前我有一个验证,当单击提交按钮时显示错误消息:

代码如下:

  1. useForm 挂钩
import { useState, useEffect } from 'react';

const useForm = (callback, validate, post) => {
    const [values, setValues] = useState(post || {});
  const [errors, setErrors] = useState({});
  const [isSubmitting, setIsSubmitting] = useState(false);

  useEffect(() => {
    if (Object.keys(errors).length === 0 && isSubmitting) {
      callback();
    }
  }, [errors]);

  const handleSubmit = (event) => {
        if (event) event.preventDefault();
        console.log('values in useForm', values)
        setErrors(validate(values))
    setIsSubmitting(true);
  };

    const handleInputChange = (event) => {
        event.persist();
    setValues(values => ({ ...values, [event.target.name]: event.target.value }));
    };
    


  return {
    handleInputChange,
        handleSubmit,
    values,
    errors,
  }
};

export default useForm;

  1. 验证函数
const validate = (values) => {
    const errors = {};
    
    if (!values.title) {
        errors.title = 'Title is required'
    } else if (values.title.length < 5) {
    errors.title = 'Title must be at least 5 characters long'
    }

    if (!values.body) {
        errors.body = "Blog body is required"
    } else if (values.body.length < 2 || values.body.length > 20) {
        errors.body = "Text has to be between 2 and 20 characters long"
    }

    if (!values.author) {
    errors.author = "The author's name is required"
    }
    
    if (!values.number) {
        errors.number = "A number is required"
    }
    
 if (!values.email) {
         errors.email = 'Email is required';
 } else if (
         !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
 ) {
         errors.email = 'Invalid email address';
 }

 return errors;
}
export default validate;
  1. 表单组件
import { useHistory } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import  useForm from '../hooks/useForm';
import { addPost } from '../actions';
import validate from '../helpers/validate';


const CreateForm = () => {
    const dispatch = useDispatch();
    const history = useHistory();
    const { values, handleInputChange, handleSubmit, errors } = useForm(submit, validate)

    const { title, body, author, number, email } = values;
    
    function submit() {
        console.log("No errors", values)
        const post = values;
      console.log('Submit form', post)
      dispatch(addPost(post)) 
      history.push('/');
    }
    

    return ( 
        <div className="create">
            <h2>Add a new blog</h2>
            <form onSubmit={handleSubmit} noValidate>
                <label>Blog title:</label>
                <input
                    type="text"
                    required 
                    name="title"
                    value={title || ""}
                    onChange={handleInputChange}
                    className={errors.title ? 'red-border' : ""}
                />
              {errors.title && (<p className="danger">{errors.title}</p>)}

                <label>Blog body:</label>
                <textarea
                    required
                    name="body"
                    value={body || ""}
                    onChange={handleInputChange}
                    className={errors.body ? 'red-border' : ""}
                />
                {errors.body && (
          <p className="danger">{errors.body}</p>
        )}
                <label>Author:</label>
                <input
                    type="text"
                    required
                    name="author"
                    value={author || ""}
                    onChange={handleInputChange}
                    className={errors.author ? 'red-border' : ""}
                />
                {errors.author && (
          <p className="danger">{errors.author}</p>
        )}
                <label>Number:</label>
                <input
                    type="number"
                    required
                    name="number"
                    value={number || ""}
                    onChange={handleInputChange}
                    className={errors.number ? 'red-border' : ""}
                />
                  {errors.number && (
          <p className="danger">{errors.number}</p>
        )}
                <label>Email:</label>
                <input
                    type="text"
                    required
                    name="email"
                    value={email || ""}
                    onChange={handleInputChange}
                    className={errors.email ? 'red-border' : ""}
                />
                  {errors.email && (
          <p className="danger">{errors.email}</p>
        )}
                <button>Save</button>
            </form>
        </div>
    );
}
 
export default CreateForm;

【问题讨论】:

  • 只需在handleInputChange 中调用setErrors,而不是在handleSubmit 中调用。如果我正确理解了您的问题,那就是它的全部内容
  • 不行,我试过了。
  • 您需要告诉我们您尝试了什么以及您的意思是什么不起作用:您遇到了哪个错误等。无论如何,请稍等,我会给您一个简单的示例代码沙盒
  • 我就是这么做的,我在 useForm 挂钩中创建了一个新函数 validateInput,我在其中调用了 setErrors。 const validateInput = (e) => {setErrors(validate(e.target.value))}。然后我在每个输入字段 onBlur={validateInput} 上调用 valideteInput。我在控制台中没有收到任何错误,但是当我散焦一个字段时,我会得到所有字段的所有错误,而不仅仅是散焦字段。我认为问题出在 validate 函数中,因为它适用于所有值,但我不确定。
  • 我相信你说对了一半:你的 validate 函数会生成一个错误对象,然后你用 setErrors 覆盖它而不传播状态。查看答案中的代码框以了解如何解决您的问题: setErrors({...errors, []})

标签: javascript reactjs forms validation redux


【解决方案1】:

正如 cmets 中所讨论的,当您想要更新您的错误帮助程序时,您只需要调用您的 setError 即可。这是一个现场示例,如果您在任何字段中键入“错误”,则会标记错误:https://codesandbox.io/s/wispy-monad-3t8us?file=/src/App.js

const validateInputs = (e) => {
    console.log("validating inputs");
    if (e.target.value === "error")
      setErrors({ ...errors, [e.target.name]: true });
    else setErrors({ ...errors, [e.target.name]: false });
  };

        <input
          type="text"
          required
          name="title"
          value={values.title}
          onChange={handleInputChange}
          style={errors.title ? { border: "2px solid red" } : null}
          onBlur={validateInputs}
        />

【讨论】:

    【解决方案2】:

    正如您在问题中所说,您应该在onBlur 中调用validate() 而不是在onSubmit 中。

    因此,只需在您的每个输入中添加 onBlur 事件:

               <input
                    type="number"
                    required
                    name="number"
                    onBlur={validate}
                    onChange={handleInputChange}
                />
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-29
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      相关资源
      最近更新 更多