【问题标题】:How do I add validation to the form in my React component?Reactjs - 表单输入验证
【发布时间】:2017-05-08 21:03:35
【问题描述】:

我的联系方式如下,

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

需要为所有字段添加验证。谁能帮我在这个反应表单中添加验证?

【问题讨论】:

  • 验证规则是什么?不能为空,字符限制或什么。如果您添加,我可以提供帮助。
  • @FurkanO 姓名 - 不能为空且只能为字母,电子邮件 - 不能为空且有效,电话 - 不能为空,仅限 10 个且仅限数字,地址和消息 - 不能空
  • 有一个包:react-form.
  • 这个包可以帮助react-jsonschema-form-validation。它使用强大的 JSON Schema 来描述数据。

标签: javascript node.js reactjs forms validation


【解决方案1】:

你应该避免使用 refs,你可以使用 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.

希望这会有所帮助。

【讨论】:

  • 不错的选择,但为什么要避免 ref ?任何原因,对于您调用函数的每个输入,是否正确?是否有任何选项可以通过单击表单提交获得全部价值
  • 很好的解决方案,但是有一个错误:一个组件正在更改一个不受控制的文本类型的输入以进行控制。输入元素不应从不受控切换到受控(反之亦然)。决定在组件的生命周期内使用受控输入元素还是不受控输入元素。
  • 很好的答案伙伴,不像其他人只是想建议一些第三方库来填补他们的部分。我也非常喜欢您在“handleValidation”定义的开头首先将变量复制到本地而不是直接引用它们的想法。
  • 一个与 OP 问题并不真正相关的问题,但我在一些与 js 相关的官方文档中也看到了很多:你为什么决定使用 let 变量 fieldserrors 而不是 constconst 在这两种情况下都有效。这还重要吗?
  • @Boky,@Vano。我得到了“受控输入不受控”的错误。要修复它,请使用this.state = { fields: {"name": "", "email":"", "phone": "", "address": ""}, errors: {} } 初始化您的状态。有关此的更多信息,请查看此处。 stackoverflow.com/questions/47012169/…
【解决方案2】:

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

<input type="text" placeholder="Your Name" required />

【讨论】:

  • 我不知道为什么还没有人对此表示赞同。它使用简单明了的内置 html 功能来满足 OP 的要求。如果除了检查是否填写了必填字段之外还有更多需要验证的内容,那么另一个答案似乎是合适的,但在这种情况下,一个简单的 required 道具正是需要的。
【解决方案3】:

我已获取您的代码并使用库 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>
    );
  }
}

截图:

这是一个快速破解。如需正确的演示,请查看https://github.com/tkrotoff/react-form-with-constraints#examples

【讨论】:

    【解决方案4】:
    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】:

      使用 React Hook,表单变得超级简单(React Hook 表单: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>
        );
      }
      

      【讨论】:

      • React 钩子表单看起来很棒!谢谢!
      【解决方案6】:

      更简洁的方法是使用 joi-browser 包。在该状态下,您应该拥有包含表单中所有错误的错误对象。最初它应该设置为一个空对象。 创建架构;

      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();
        };
      

      【讨论】:

      • 赞成将 Joi 作为验证者。但请注意 joi-browser 已被弃用,建议使用 joi 本身。上面的代码会有所改变。 joi.dev/api/?v=17.3.0
      【解决方案7】:

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

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

      【讨论】:

        【解决方案8】:

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

        【讨论】:

          【解决方案9】:

          试试powerform-react。它基于powerform,这是一个超级便携的 Javascript 表单库。一旦学会,它可以在任何框架中使用。它甚至适用于原生 Javascript。

          Checkout this simple form 使用powerform-react

          还有一个complex example

          【讨论】:

            【解决方案10】:

            假设你知道 react 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 也支持它,它允许您添加不仅仅是简单的验证。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-01-06
              • 2015-09-05
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多