There is no doubt that form validation in react is tedious, especially for dynamically added or deleted forms, its validation logic is more complex. At present, the UI framework uses material ui, but its form processing is not ideal. Then, another UI framework ant design is studied. Its processing of forms greatly facilitates the writing of logic. It uses async validator to process the validation logic
There is no doubt that it is unrealistic to change the framework at present, so I want to introduce async validator directly. Here is a simple use, and the specific information can be viewed on github
validate.js
import Schema from 'async-validator';
/*
* @params form: {
* descriptor: Validation rule
* source: Fields to be verified
* callback: Asynchronous verification callback function
* }
*
* @return errInfo {
* isAllValid: Verify pass
* errors: Validation failed field information
* }
* Whether the verification result is successful or failed, the result information will be written into errors, which is convenient for the caller to obtain the verification result information directly through array subscript
* */
function validate (form) {
let errInfo = {};
let errStatus = [];
let descriptor = form.descriptor;
let validator = new Schema(descriptor);
validator.validate(form.source, {
firstFields: true // If a field corresponds to multiple validation rules, only the first rule information that fails to be validated will be displayed, and subsequent rule validation will not be performed again
}, (errors, fields) => {
if (errors) {
/* For asynchronous verification, you need to pass in the callback function */
errors.forEach(item => {
errStatus.push(item.message.errStatus);
});
errInfo.errors = errors;
errInfo.isAllValid = !errStatus.includes(true);
form.callback && form.callback(errInfo);
}
});
return errInfo;
}
export default validate;
Form.js
/**
* Created by wxw on 18-4-26.
*/
import React from 'react';
import {inject} from 'mobx-react';
import { withStyles } from 'material-ui/styles';
import validate from '../utils/validate';
import {formTest2} from '../utils/validateRules';
import Input, { InputLabel } from 'material-ui/Input';
import { FormControl, FormHelperText } from 'material-ui/Form';
import { MenuItem } from 'material-ui/Menu';
import Select from 'material-ui/Select';
import Button from 'material-ui/Button';
const styles = theme => ({
container: {
display: 'flex',
flexWrap: 'wrap',
},
formControl: {
margin: theme.spacing.unit,
},
button: {
margin: theme.spacing.unit,
color: '#fff'
},
});
@inject('rootStore')
@withStyles(styles)
class FormTest2 extends React.Component {
state = {
name: {
value: '',
errStatus: false,
errMsg: 'Please input name'
},
age: {
value: '',
errStatus: false,
errMsg: 'Please choose age'
}
};
handleChange =(field) => event => {
if (field === 'name') {
this.setState({ name: Object.assign(this.state.name, {value: event.target.value}) });
} else if (field === 'age') {
this.setState({ age: Object.assign(this.state.age, {value: event.target.value}) });
}
};
handleCheck = (field) => () => {
if (field === 'name') {
let errInfo = validate({
descriptor: formTest2,
source: {
name: this.state.name.value,
}
});
this.setState({ name: errInfo.errors[0].message});
} else if (field === 'age') {
let errInfo = validate({
descriptor: formTest2,
source: {
age: this.state.age.value,
}
});
this.setState({ age: errInfo.errors[1].message });
}
};
handleSubmit = () => {
let {name, age} = this.state;
let errInfo = validate({
descriptor: formTest2,
source: {
name: name.value,
age: age.value
}
});
errInfo.errors.forEach(item => {
this.setState({
[item.field]: item.message
});
});
if (errInfo.isAllValid) {
console.log('Verify success');
} else {
console.log('Validation failed');
}
};
render () {
const { classes } = this.props;
const {name, age} = this.state;
return (
<div className="form2">
<FormControl className={classes.formControl} error={name.errStatus}>
<InputLabel htmlFor="name-simple">Name</InputLabel>
<Input id="name-simple" value={name.value} onChange={this.handleChange('name')} placeholder="placeholder" onBlur={this.handleCheck('name')} />
<FormHelperText id="name-simple">{name.errMsg}</FormHelperText>
</FormControl>
<FormControl className={classes.formControl} error={age.errStatus}>
<InputLabel htmlFor="age-simple">Age</InputLabel>
<Select
value={age.value}
onChange={this.handleChange('age')}
onBlur={this.handleCheck('age')}
inputProps={{
name: 'age',
id: 'age-simple',
}}
>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
<FormHelperText id="age-simple">{age.errMsg}</FormHelperText>
</FormControl>
<Button variant="raised" color="primary" className={classes.button} onClick={this.handleSubmit}>
//Submission
</Button>
</div>
)
}
}
export default FormTest2;
validateRules.js
/**
* Created by wxw on 18-4-26.
*/
export const formTest2 = {
name: {
validator(rule, value, callback, source, options) {
/* callback It must be executed once, with parameter as error message, without parameter as correct */
if (value) {
callback({
errMsg: "Please input name",
value,
errStatus: false
});
} else {
callback({
errMsg: "name Can not be empty",
value,
errStatus: true
});
}
}
},
age: {
validator(rule, value, callback, source, options) {
/* callback It must be executed once, with parameter as error message, without parameter as correct */
if (value) {
callback({
errMsg: "Please choose age",
value,
errStatus: false
});
} else {
callback({
errMsg: "Necessary option",
value,
errStatus: true
});
}
}
},
};
To sum up, it is a small demo. On this basis, it can be further encapsulated for use