[英]How do I add validation to the form in my React component?
我的联系页面表单如下,
<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>
需要为所有字段添加验证。 谁能帮我在这个反应表单中添加验证?
您应该避免使用 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'));
在此示例中,我仅对电子邮件和姓名进行了验证,但您知道如何进行验证。 其余的你可以自己做。
也许有更好的方法,但你会明白的。
希望这可以帮助。
我已经采用了您的代码并使用库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
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;
试试这个,例如,下面输入标签中的 required 属性将确保 name 字段不应该被提交为空。
<input type="text" placeholder="Your Name" required />
使用 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>
);
}
2022年
React 建议使用 3 种方法来处理表单:
受控组件- 在 HTML 中,<input>、<textarea> 和 <select> 等表单元素通常会维护自己的状态并根据用户输入更新状态。 在 React 中,可变状态通常保存在组件的状态属性中,并且仅通过 setState() 更新。 我们可以通过使 React 状态成为“单一事实来源”来将两者结合起来。 然后呈现表单的 React 组件还控制在后续用户输入时该表单中发生的事情。 以这种方式由 React 控制其值的输入表单元素称为“受控组件”。
不受控制的组件- 使用受控组件有时会很乏味,因为您需要为数据可以更改的每种方式编写一个事件处理程序,并通过 React 组件传输所有输入状态。 当您将预先存在的代码库转换为 React,或将 React 应用程序与非 React 库集成时,这会变得特别烦人。 在这些情况下,您可能想要检查不受控制的组件,这是实现输入表单的替代技术。
成熟的解决方案——如果您正在寻找一个完整的解决方案,包括验证、跟踪访问的字段和处理表单提交,Formik 是最受欢迎的选择之一。 然而,它建立在受控组件和管理状态的相同原则之上——所以不要忽视学习它们。
所有方法都适用于反应钩子。
首先考虑哪个组件更适合您的需求,并使用其适当的验证解决方案。
更干净的方法是使用 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();
};
可能会迟到 - 如果您不想大量修改当前代码并且仍然能够在整个项目中使用类似的验证代码,您也可以尝试这个 - https://github.com/vishalvisd/反应验证器。
试试powerform-react 。 它基于powerform
,这是一个超级便携的 Javascript 表单库。 一旦学会,它就可以在任何框架中使用。 它甚至适用于 vanilla Javascript。
还有一个复杂的例子。
尝试使用这种方法https://medium.com/@krzakmarek88/complex-form-validation-in-react-hooks-cb07367196b9这是发达国家在阵营鱼钩但是当你需要它可以适应以简单的方式作出反应
假设你知道 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
支持,它允许您添加的不仅仅是简单的验证。
在您的表单中试用此验证插件,您可以在其中添加自定义验证规则。
创建组件 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`,
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.