代码之家  ›  专栏  ›  技术社区  ›  Hulk1991 moinudin

如何向React组件中的表单添加验证?

  •  90
  • Hulk1991 moinudin  · 技术社区  · 9 年前

    我的联系页面表单如下:,

    <form name="contactform" onSubmit={this.contactSubmit.bind(this)}>
      <div className="col-md-6">
        <fieldset>
          <input ref="name" type="text" size="30" placeholder="Name"/>
          <br/>
          <input refs="email" type="text" size="30" placeholder="Email"/>
          <br/>
          <input refs="phone" type="text" size="30" placeholder="Phone"/>
          <br/>
          <input refs="address" type="text" size="30" placeholder="Address"/>
          <br/>
        </fieldset>
      </div>
      <div className="col-md-6">
        <fieldset>
          <textarea refs="message" cols="40" rows="20"
                    className="comments" placeholder="Message"/>
        </fieldset>
      </div>
      <div className="col-md-12">
        <fieldset>
          <button className="btn btn-lg pro" id="submit"
                  value="Submit">Send Message</button>
        </fieldset>
      </div>
    </form>
    

    需要为所有字段添加验证。有人可以帮助我在这个react表单中添加验证吗?

    12 回复  |  直到 4 年前
        1
  •  180
  •   Yana Trifonova    5 年前

    您应该避免使用ref,您可以使用 onChange 作用

    每次更改时,更新更改字段的状态。

    然后,您可以轻松地检查该字段是否为空或您想要的其他内容。

    您可以执行以下操作:

    class Test extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          fields: {},
          errors: {},
        };
      }
    
      handleValidation() {
        let fields = this.state.fields;
        let errors = {};
        let formIsValid = true;
    
        //Name
        if (!fields["name"]) {
          formIsValid = false;
          errors["name"] = "Cannot be empty";
        }
    
        if (typeof fields["name"] !== "undefined") {
          if (!fields["name"].match(/^[a-zA-Z]+$/)) {
            formIsValid = false;
            errors["name"] = "Only letters";
          }
        }
    
        //Email
        if (!fields["email"]) {
          formIsValid = false;
          errors["email"] = "Cannot be empty";
        }
    
        if (typeof fields["email"] !== "undefined") {
          let lastAtPos = fields["email"].lastIndexOf("@");
          let lastDotPos = fields["email"].lastIndexOf(".");
    
          if (
            !(
              lastAtPos < lastDotPos &&
              lastAtPos > 0 &&
              fields["email"].indexOf("@@") == -1 &&
              lastDotPos > 2 &&
              fields["email"].length - lastDotPos > 2
            )
          ) {
            formIsValid = false;
            errors["email"] = "Email is not valid";
          }
        }
    
        this.setState({ errors: errors });
        return formIsValid;
      }
    
      contactSubmit(e) {
        e.preventDefault();
    
        if (this.handleValidation()) {
          alert("Form submitted");
        } else {
          alert("Form has errors.");
        }
      }
    
      handleChange(field, e) {
        let fields = this.state.fields;
        fields[field] = e.target.value;
        this.setState({ fields });
      }
    
      render() {
        return (
          <div>
            <form
              name="contactform"
              className="contactform"
              onSubmit={this.contactSubmit.bind(this)}
            >
              <div className="col-md-6">
                <fieldset>
                  <input
                    ref="name"
                    type="text"
                    size="30"
                    placeholder="Name"
                    onChange={this.handleChange.bind(this, "name")}
                    value={this.state.fields["name"]}
                  />
                  <span style={{ color: "red" }}>{this.state.errors["name"]}</span>
                  <br />
                  <input
                    refs="email"
                    type="text"
                    size="30"
                    placeholder="Email"
                    onChange={this.handleChange.bind(this, "email")}
                    value={this.state.fields["email"]}
                  />
                  <span style={{ color: "red" }}>{this.state.errors["email"]}</span>
                  <br />
                  <input
                    refs="phone"
                    type="text"
                    size="30"
                    placeholder="Phone"
                    onChange={this.handleChange.bind(this, "phone")}
                    value={this.state.fields["phone"]}
                  />
                  <br />
                  <input
                    refs="address"
                    type="text"
                    size="30"
                    placeholder="Address"
                    onChange={this.handleChange.bind(this, "address")}
                    value={this.state.fields["address"]}
                  />
                  <br />
                </fieldset>
              </div>
            </form>
          </div>
        );
      }
    }
    
    React.render(<Test />, document.getElementById("container"));
        
    
    

    在本例中,我只对电子邮件和姓名进行了验证,但您知道如何进行验证。剩下的你可以自己做。

    也许有更好的方法,但你会明白的。

    Here is fiddle.

    希望这有帮助。

        2
  •  31
  •   Yash Marmat    5 年前

    例如, 以下输入标记中的必需属性将确保名称字段不应为空提交。

    <input type="text" placeholder="Your Name" required />
    
        3
  •  10
  •   tanguy_k streuspeicher    8 年前

    我已经使用了您的代码并使用库进行了修改 react-form-with-constraints : https://codepen.io/tkrotoff/pen/LLraZp

    const {
      FormWithConstraints,
      FieldFeedbacks,
      FieldFeedback
    } = ReactFormWithConstraints;
    
    class Form extends React.Component {
      handleChange = e => {
        this.form.validateFields(e.target);
      }
    
      contactSubmit = e => {
        e.preventDefault();
    
        this.form.validateFields();
    
        if (!this.form.isValid()) {
          console.log('form is invalid: do not submit');
        } else {
          console.log('form is valid: submit');
        }
      }
    
      render() {
        return (
          <FormWithConstraints
            ref={form => this.form = form}
            onSubmit={this.contactSubmit}
            noValidate>
    
            <div className="col-md-6">
              <input name="name" size="30" placeholder="Name"
                     required onChange={this.handleChange}
                     className="form-control" />
              <FieldFeedbacks for="name">
                <FieldFeedback when="*" />
              </FieldFeedbacks>
    
              <input type="email" name="email" size="30" placeholder="Email"
                     required onChange={this.handleChange}
                     className="form-control" />
              <FieldFeedbacks for="email">
                <FieldFeedback when="*" />
              </FieldFeedbacks>
    
              <input name="phone" size="30" placeholder="Phone"
                     required onChange={this.handleChange}
                     className="form-control" />
              <FieldFeedbacks for="phone">
                <FieldFeedback when="*" />
              </FieldFeedbacks>
    
              <input name="address" size="30" placeholder="Address"
                     required onChange={this.handleChange}
                     className="form-control" />
              <FieldFeedbacks for="address">
                <FieldFeedback when="*" />
              </FieldFeedbacks>
            </div>
    
            <div className="col-md-6">
              <textarea name="comments" cols="40" rows="20" placeholder="Message"
                        required minLength={5} maxLength={50}
                        onChange={this.handleChange}
                        className="form-control" />
              <FieldFeedbacks for="comments">
                <FieldFeedback when="*" />
              </FieldFeedbacks>
            </div>
    
            <div className="col-md-12">
              <button className="btn btn-lg btn-primary">Send Message</button>
            </div>
          </FormWithConstraints>
        );
      }
    }
    

    截图:

    form validation screenshot

    这是一个快速的黑客。要获得正确的演示,请检查 https://github.com/tkrotoff/react-form-with-constraints#examples

        4
  •  6
  •   user10045612 user10045612    8 年前
    import React from 'react';
    import {sendFormData} from '../services/';
    
    class Signup extends React.Component{
      constructor(props){
        super(props);
         this.state = {
           isDisabled:true
         }                                                                                                 
         this.submitForm = this.submitForm.bind(this);
      }
      validateEmail(email){
       const pattern = /[a-zA-Z0-9]+[\.]?([a-zA-Z0-9]+)?[\@][a-z]{3,9}[\.][a-z]{2,5}/g;
       const result = pattern.test(email);
       if(result===true){
         this.setState({
           emailError:false,
           email:email
         })
       } else{
         this.setState({
           emailError:true
         })
       }
     }
     handleChange(e){
      const target = e.target;
      const value = target.type === 'checkbox' ? target.checked : target.value;
      const name = target.name;
      this.setState({
        [name]: value
      });
      if(e.target.name==='firstname'){
        if(e.target.value==='' || e.target.value===null ){
          this.setState({
            firstnameError:true
          })
        } else {
          this.setState({
            firstnameError:false,     
            firstName:e.target.value
          })
        }
      }
      if(e.target.name==='lastname'){
        if(e.target.value==='' || e.target.value===null){
          this.setState({
            lastnameError:true
          })
        } else {
          this.setState({
            lastnameError:false,
            lastName:e.target.value
          })
        }
      }
      if(e.target.name==='email'){
       this.validateEmail(e.target.value);
      }
      if(e.target.name==='password'){
        if(e.target.value==='' || e.target.value===null){
          this.setState({
            passwordError:true
          })
        } else {
          this.setState({
            passwordError:false,
            password:e.target.value
          })
        }
     }
     if(this.state.firstnameError===false && this.state.lastnameError===false && 
      this.state.emailError===false && this.state.passwordError===false){
        this.setState({
          isDisabled:false
        })
     }
    }
    submitForm(e){
      e.preventDefault();
      const data = {
       firstName: this.state.firstName,
       lastName: this.state.lastName,
       email: this.state.email,
       password: this.state.password
      }
      sendFormData(data).then(res=>{
        if(res.status===200){
          alert(res.data);
          this.props.history.push('/');
        }else{
    
        } 
      });
     }
    render(){
    return(
      <div className="container">
        <div className="card card-login mx-auto mt-5">
          <div className="card-header">Register here</div>
            <div className="card-body">
                <form id="signup-form">
                  <div className="form-group">
                    <div className="form-label-group">
                      <input type="text" id="firstname" name="firstname" className="form-control" placeholder="Enter firstname" onChange={(e)=>{this.handleChange(e)}} />
                      <label htmlFor="firstname">firstname</label>
                      {this.state.firstnameError ? <span style={{color: "red"}}>Please Enter some value</span> : ''} 
                    </div>
                  </div>
                  <div className="form-group">
                    <div className="form-label-group">
                      <input type="text" id="lastname" name="lastname" className="form-control" placeholder="Enter lastname" onChange={(e)=>{this.handleChange(e)}} />
                      <label htmlFor="lastname">lastname</label>
                      {this.state.lastnameError ? <span style={{color: "red"}}>Please Enter some value</span> : ''}
                    </div>
                  </div>
                  <div className="form-group">
                    <div className="form-label-group">
                      <input type="email" id="email" name="email" className="form-control" placeholder="Enter your email" onChange={(e)=>{this.handleChange(e)}} />
                      <label htmlFor="email">email</label>
                      {this.state.emailError ? <span style={{color: "red"}}>Please Enter valid email address</span> : ''}
                    </div>
                  </div>                
                  <div className="form-group">
                    <div className="form-label-group">
                      <input type="password" id="password" name="password" className="form-control" placeholder="Password" onChange={(e)=>{this.handleChange(e)}} />
                      <label htmlFor="password">Password</label>
                      {this.state.passwordError ? <span style={{color: "red"}}>Please enter some   value</span> : ''}
                    </div>
                  </div>                
                  <button className="btn btn-primary btn-block" disabled={this.state.isDisabled} onClick={this.submitForm}>Signup</button>
                </form>
            </div>
          </div>
        </div>
      );
     }
    }
    export default Signup;
    
        5
  •  5
  •   Bill    7 年前

    使用React挂钩,表单变得超级简单(React挂钩表单: https://github.com/bluebill1049/react-hook-form )

    我已经重用了您的html标记。

    import React from "react";
    import useForm from 'react-hook-form';
    
    function Test() {
      const { useForm, register } = useForm();
      const contactSubmit = data => {
        console.log(data);
      };
    
      return (
        <form name="contactform" onSubmit={contactSubmit}>
          <div className="col-md-6">
            <fieldset>
              <input name="name" type="text" size="30" placeholder="Name" ref={register} />
              <br />
              <input name="email" type="text" size="30" placeholder="Email" ref={register} />
              <br />
              <input name="phone" type="text" size="30" placeholder="Phone" ref={register} />
              <br />
              <input name="address" type="text" size="30" placeholder="Address" ref={register} />
              <br />
            </fieldset>
          </div>
          <div className="col-md-6">
            <fieldset>
              <textarea name="message" cols="40" rows="20" className="comments" placeholder="Message" ref={register} />
            </fieldset>
          </div>
          <div className="col-md-12">
            <fieldset>
              <button className="btn btn-lg pro" id="submit" value="Submit">
                Send Message
              </button>
            </fieldset>
          </div>
        </form>
      );
    }
    
        6
  •  2
  •   Yilmaz    7 年前

    更干净的方法是使用joi浏览器包。在这种状态下,您应该有一个包含表单中所有错误的错误对象。最初,它应该设置为空对象。 创建模式;

    import Joi from "joi-browser";
    schema = {
        username: Joi.string()
          .required()
          .label("Username")
          .email(),
        password: Joi.string()
          .required()
          .label("Password")
          .min(8)
          .regex(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{8,1024}$/) //special/number/capital
       };
    

    然后使用模式验证表单:

    validate = () => {
        const options = { abortEarly: false };
        const result = Joi.validate(this.state.data, this.schema, options);
        console.log(data) // always analyze your data
        if (!result.error) return null; 
        const errors = {};
        for (let item of result.error.details) errors[item.path[0]] = item.message; //in details array, there are 2 properties,path and message.path is the name of the input, message is the error message for that input.
        return errors;
      };
    

    在提交表单之前,请检查表单:

    handleSubmit = e => {
        e.preventDefault();
        const errors = this.validate(); //will return an object
        console.log(errors);
        this.setState({ errors: errors || {} }); //in line 9 if we return {}, we dont need {} here
        if (errors) return;
        //so we dont need to call the server
        alert("success");
        //if there is no error call the server
        this.dosubmit();
      };
    
        7
  •  2
  •   Gokulakannan T    6 年前

    我们有很多选项来验证react js表单。也许npm包有自己的局限性。根据您的需要,您可以选择正确的验证程序包。我想推荐一些,如下所列。

    如果有人知道比这更好的解决方案,请将其放在评论部分,供其他人参考。

        8
  •  2
  •   Gal Margalit    4 年前

    2022
    反应建议3 approaches 处理表单:

    1. Controlled components -在HTML中;输入>&书信电报;textarea>,并且<选择>通常维护它们自己的状态并基于用户输入来更新它。在React中,可变状态通常保留在组件的状态属性中,并且仅使用setState()更新。我们可以通过使反应状态成为真理的唯一来源来将两者结合起来。然后,呈现表单的React组件还控制后续用户输入时表单中发生的情况。以这种方式由React控制其值的输入表单元素称为受控组件。

    2. Uncontrolled components -有时使用受控组件可能会很乏味,因为您需要为数据的每一种变化编写事件处理程序,并通过React组件传输所有输入状态。当您将预先存在的代码库转换为React,或者将React应用程序与非React库集成时,这可能会变得特别恼人。在这些情况下,您可能需要检查非受控组件,这是实现输入表单的另一种技术。

    3. Fully-Fledged Solutions -如果您正在寻找一个完整的解决方案,包括验证、跟踪访问的字段和处理表单提交,Formik是一个流行的选择。然而,它建立在受控组件和管理状态的相同原理之上,所以不要忽略学习它们。


    首先考虑哪个组件更适合您的需求,并使用其适当的验证解决方案。

        9
  •  1
  •   Preety Singh    8 年前

    回答可能会晚-如果您不想大量修改当前代码,但仍然可以在整个项目中使用类似的验证代码,您也可以尝试这个- https://github.com/vishalvisd/react-validator .

        10
  •  1
  •   Asur    6 年前

    尝试 powerform-react .它是基于 powerform 这是一个超级可移植的Javascript表单库。一旦学会,它可以在任何框架中使用。它甚至适用于普通Javascript。

    Checkout this simple form 使用 powerform react

    还有一个 complex example .

        11
  •  1
  •   Sanan Ali    5 年前

    假设你知道反应 useState Hook ,如果您的表单很简单,您可以使用 state 变量来保存每个输入字段的值。然后加上 onChange 每个输入字段上的处理函数将更新状态变量。最后,您可以检查存储在状态变量中的值,以确保所有输入字段都有一些值。下面是一个简单的例子。

    import { useState } from "react";
    
    export default function App() {
      const [name, setName] = useState("");
      const [email, setEmail] = useState("");
      const onChangeHandler = (fieldName, value)=>{
        if(fieldName === "name"){
          setName(value);
        }
        else if(fieldName==="email"){
          setEmail(value);
        }
      }
      const onSubmitHandler = (e)=>{
        e.preventDefault();
        if(name.trim()==="" || email.trim() ==""){
          alert("required both field");
        }
        else{
          alert(name+" " +email);
          setName("");
          setEmail("");
        }
      }
      return (
        <div className="App">
          <form onSubmit={(e)=>{onSubmitHandler(e)}}>
            <input type="text" value={name} onChange={(e)=>{ onChangeHandler("name",e.target.value)}} /> <br/>
             <input type="email"  value={email} onChange={(e)=>{ onChangeHandler("email",e.target.value)}} /> <br/>
             <input type="submit" value="Submit" />
            </form>
        </div>
      );
    }
    

    然而,如果您有一个复杂的表单,很难将每个值保存在状态变量中,然后对每个字段使用验证。对于复杂表单,建议使用 Formik 这将为您做一切,您可以使用 Yup Formik 这将允许您添加不仅仅是简单的验证。

        12
  •  0
  •   aman    4 年前

    创建一个组件FormValidation.js

      import { useState } from "react";
    
      const FormValidation = ({ validationRules, formInput }) => {
        const [errors, setErrors] = useState(null);
    
        const validation = () => {
          // define a empty object to store errors.
          let allErrors = {};
          // Run loop on validation object
          Object.keys(validationRules).forEach((name) => {
            // name is the name of input field
            const rulesArr = validationRules[name];
    
            // Run loop on validation array applied on that input
            rulesArr.forEach((rule) => {
              // Skip if any error message is already stored in allErrors object
              if (!allErrors[name]) {
                let result;
                // If rule is an array than it is a type of a function with parameter
                switch (Array.isArray(rule)) {
                  case true: {
                    // take the function name and parameter value from rule array
                    const [functionName, paramValue] = rule;
                    // call validation function
    
                    result = functionName(formInput, name, paramValue);
                    break;
                  }
    
                  default:
                    // call validation function
                    result = rule(formInput, name);
                    break;
                }
                if (result) {
                  // append error in object
                  allErrors = { ...allErrors, ...result };
                }
              }
            });
          });
    
          return allErrors;
        };
    
        const validate = () =>
          new Promise((resolve, reject) => {
            const errorObj = validation();
    
            if (Object.keys(errorObj).length === 0) {
              setErrors({});
              resolve("Success");
            } else {
              setErrors(errorObj);
              reject(Error("Some Error Occurred"));
            }
          });
    
        return { validate, errors, setErrors };
      };
    
      export const required = (formInputs, inputName) =>
        !formInputs[inputName] && { [inputName]: "This field is required" };
    
      function emailPattern(email) {
        return String(email)
          .toLowerCase()
          .match(
            /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
          );
      }
    
      export const email = (formInputs, inputName) =>
        !emailPattern(formInputs[inputName]) && {
          [inputName]: "Please enter valid email",
        };
    
      export function passwordPattern(formInputs, inputName) {
        const value = formInputs[inputName];
    
        let error;
        if (value.length < 8) {
          error = "Your password must be at least 8 characters";
        }
        if (value.search(/[a-z]/i) < 0) {
          error = "Your password must contain at least one letter.";
        }
        if (value.search(/[0-9]/) < 0) {
          error = "Your password must contain at least one digit.";
        }
    
        if (value.search(/[ `!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/) < 0) {
          error = "Your password must contain at least one special character.";
        }
    
        return (
          error && {
            [inputName]: error,
          }
        );
      }
    
      export const maxLength = (formInputs, inputName, paramValue) =>
        formInputs[inputName].length > paramValue && {
          [inputName]: `Maximum characters are ${paramValue}`,
        };
    
      export const minLength = (formInputs, inputName, paramValue) =>
        formInputs[inputName].length < paramValue && {
          [inputName]: `Minimum characters are ${paramValue}`,
        };
    
      export default FormValidation;
    

    我想在Login.js中实现验证

        import React, { useState } from "react";
        import { Button, Form } from "react-bootstrap";
        import FormValidation, {
          required,
          email,
          passwordPattern,
        } from "utils/FormValidation";
    
        const Login = () => {
          const [formInput, setFormInput] = useState({
            email: "",
            password: "",
          });
    
          const { validate, errors, setErrors } = FormValidation({
            validationRules: {
              email: [required, email],
              password: [required, passwordPattern],
            },
            formInput,
          });
    
          const handleChange = (e) => {
            setFormInput({ ...formInput, [e.target.name]: e.target.value });
          };
    
          const handleSubmit = (e) => {
            e.preventDefault();
            validate().then(() => {
              //do whatever you want
              console.log(formInput);
              // you can set server error manually
              setErrors({ email: "Email already exist" });
            });
          };
    
          return (
            <section className="gradient-form" style={{ backgroundColor: "#eee" }}>
              <div className="container py-5 h-100">
                <div className="row d-flex justify-content-center align-items-center h-100">
                  <div className="col-xl-10">
                    <div className="card rounded-3 text-black">
                      <div className="row g-0">
                        <div className="col-lg-6">
                          <div className="card-body p-md-5 mx-md-4">
                            <Form onSubmit={handleSubmit}>
                              <p>Please login to your account</p>
                              <Form.Group className="mb-3" controlId="formBasicEmail">
                                <Form.Control
                                  type="text"
                                  name="email"
                                  placeholder="Enter email"
                                  onChange={handleChange}
                                />
                                {errors?.email && <span>{errors.email}</span>}
                              </Form.Group>
    
                              <Form.Group
                                className="mb-3"
                                controlId="formBasicPassword"
                              >
                                <Form.Control
                                  type="password"
                                  name="password"
                                  placeholder="Password"
                                  onChange={handleChange}
                                />
                                {errors?.password && <span>{errors.password}</span>}
                              </Form.Group>
                              <Form.Group
                                className="mb-3"
                                controlId="formBasicCheckbox"
                              >
                                <Form.Check type="checkbox" label="Check me out" />
                              </Form.Group>
                              <div className="d-grid gap-2 mb-3">
                                <Button
                                  variant="primary"
                                  type="submit"
                                  className="gradient-custom-2"
                                  size="md"
                                >
                                  Submit
                                </Button>
                              </div>
                            </Form>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </section>
          );
        };
        export default Login;
    

    现在,您可以在验证数组中传递任何自定义函数:

    const { validate, errors, setErrors } = FormValidation({
        validationRules: {
          email: [required, email],
          password: [required, passwordPattern, customFunciton],
        },
        formInput,
      });
    
    const customFunciton = (formInputs, inputName) => ({
    [inputName]: `This error is from my custom function`,
    });
    
    推荐文章