React 中表单的完整指南:如果表单无效,则禁用提交按钮

2025-06-04

React 表单完整指南

如果表单无效,则禁用“提交”按钮

以后给我写一封关于 React Forms 的信

表单在任何 Web 应用中都非常有用。与 Angular 和 AngularJS 不同,它提供了开箱即用的表单验证功能。在 React 中,你必须自己处理表单。这带来了许多复杂问题,例如如何获取表单值、如何管理表单状态、如何动态验证表单并显示验证消息。市面上有很多方法和库可以帮助你实现这些功能,但如果你像我一样讨厌依赖太多库,欢迎加入我们,我们将从头开始构建自己的表单。

表单输入框有两种类型react。分别是uncontrolled inputcontrolled input。 它们uncontrolled input类似于传统的 HTML 表单输入框,可以记住你输入的内容。我们将使用ref来获取表单值。

submitFormHandler = event => {
event.preventDefault();
console.dir(this.refs.name.value); //will give us the name value
}
render() {
return (
<div>
<form onSubmit={this.submitFormHandler}>
<div>
<input type="text" name="name" ref="name" />
</div>
</form>
</div>
);
}
submitFormHandler = event => {
event.preventDefault();
console.dir(this.refs.name.value); //will give us the name value
}
render() {
return (
<div>
<form onSubmit={this.submitFormHandler}>
<div>
<input type="text" name="name" ref="name" />
</div>
</form>
</div>
);
}

我们在 input 标签中添加了 ,ref="name"以便在表单提交时可以使用 来访问值this.refs.name.value。这样做的缺点是,你必须在需要时从字段中“拉”出值,而这可能发生在表单提交时。

也就是说controlled input,渲染表单的 React 组件也会控制后续用户输入时表单中发生的情况。也就是说,当表单值发生变化时,渲染表单的组件会将该值保存在其状态中。

import React, { Component } from 'react';
class FormComponent extends Component {
constructor () {
this.state = {
email: ''
}
}
changeHandler = event => {
this.setState({
email: event.target.value
});
}
render () {
return (
<form>
<input type="email"
name="email"
value={this.state.email}
onChange={this.changeHandler}
/>
</form>
);
}
}
export default FormComponent;
view raw form_01.js hosted with ❤ by GitHub
import React, { Component } from 'react';
class FormComponent extends Component {
constructor () {
this.state = {
email: ''
}
}
changeHandler = event => {
this.setState({
email: event.target.value
});
}
render () {
return (
<form>
<input type="email"
name="email"
value={this.state.email}
onChange={this.changeHandler}
/>
</form>
);
}
}
export default FormComponent;
view raw form_01.js hosted with ❤ by GitHub

当然,另一个组件可以处理表单状态。目标是每次输入发生变化时,changeHandler都会调用该方法并存储输入状态。因此,该组件始终拥有输入的当前值,而无需主动请求。这意味着表单组件可以立即响应输入变化;例如

  • 现场反馈,例如验证
  • 除非所有字段都包含有效数据,否则禁用按钮
  • 强制执行特定的输入格式

处理多个表单输入

在大多数情况下,我们会有多个表单输入。我们需要一种通过方法来捕获输入的方式,而不是声明多个方法来执行此操作。因此,我们将修改changeHandler如下代码:

changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
this.setState({
formControls: {
[name]: value
}
});
}
changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
this.setState({
formControls: {
[name]: value
}
});
}

由于上面修改了 changeHandler 的方式,我们的表单输入可以引用它来动态更新其状态。

import React, { Component } from 'react';
class FormContainer extends Component {
constructor () {
this.state = {
formControls: {
email: {
value: ''
},
name: {
value: ''
},
password: {
value: ''
}
}
}
}
changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
this.setState({
formControls: {
...this.state.formControls,
[name]: {
...this.state.formControls[name],
value
}
}
});
}
render() {
return (
<form>
<input type="email"
name="email"
value={this.state.formControls.email.value}
onChange={this.changeHandler}
/>
<input type="text"
name="name"
value={this.state.formControls.name.value}
onChange={this.changeHandler}
/>
<input type="password"
name="password"
value={this.state.formControls.password.value}
onChange={this.changeHandler}
/>
</form>
);
}
}
export default FormContainer;
import React, { Component } from 'react';
class FormContainer extends Component {
constructor () {
this.state = {
formControls: {
email: {
value: ''
},
name: {
value: ''
},
password: {
value: ''
}
}
}
}
changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
this.setState({
formControls: {
...this.state.formControls,
[name]: {
...this.state.formControls[name],
value
}
}
});
}
render() {
return (
<form>
<input type="email"
name="email"
value={this.state.formControls.email.value}
onChange={this.changeHandler}
/>
<input type="text"
name="name"
value={this.state.formControls.name.value}
onChange={this.changeHandler}
/>
<input type="password"
name="password"
value={this.state.formControls.password.value}
onChange={this.changeHandler}
/>
</form>
);
}
}
export default FormContainer;

创建 TextInput 组件

有不同的输入元素,例如文本、电子邮件、密码、选择选项、复选框、日期、单选按钮等。我喜欢为输入元素创建单独的自定义组件,让我们从开始text input type

import React from 'react';
import './style.css';
const TextInput = (props) => {
return (
<div className="form-group">
<input type="text" className="form-control" {...props} />
</div>
);
}
export default TextInput;
view raw TextInput.js hosted with ❤ by GitHub
import React from 'react';
import './style.css';
const TextInput = (props) => {
return (
<div className="form-group">
<input type="text" className="form-control" {...props} />
</div>
);
}
export default TextInput;
view raw TextInput.js hosted with ❤ by GitHub

注意{…props},我们使用它来将 props 分发到输入元素。我们可以像下面这样使用自定义文本输入元素:

import React, { Component } from 'react';
import TextInput from './TextInput';
class FormComponent extends Component {
constructor() {
super();
this.state = {
formControls: {
name: {
value: '',
placeholder: 'What is your name'
}
}
}
}
changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
this.setState({
formControls: {
[name]: value
}
});
}
render() {
return (
<TextInput name="name"
placeholder={this.state.formControls.name.placeholder}
value={this.state.formControls.name.value}
onChange={this.changeHandler}
/>
);
}
import React, { Component } from 'react';
import TextInput from './TextInput';
class FormComponent extends Component {
constructor() {
super();
this.state = {
formControls: {
name: {
value: '',
placeholder: 'What is your name'
}
}
}
}
changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
this.setState({
formControls: {
[name]: value
}
});
}
render() {
return (
<TextInput name="name"
placeholder={this.state.formControls.name.placeholder}
value={this.state.formControls.name.value}
onChange={this.changeHandler}
/>
);
}

验证我们的自定义 TextInput

由于我们使用了controlled input,我们可以在 formControls 状态中添加更多键来帮助验证输入。我们需要valid属性来指示输入是否有效,包含在有效validationRules之前需要检查的规则列表。input

constructor() {
super();
this.state = {
formControls: {
name: {
value: ''.
placeholder: 'What is your name',
valid: false,
touched: false,
validationRules: {
minLength: 3
}
}
}
}
}
constructor() {
super();
this.state = {
formControls: {
name: {
value: ''.
placeholder: 'What is your name',
valid: false,
touched: false,
validationRules: {
minLength: 3
}
}
}
}
}

我们的目标是,每次输入发生变化时,都要确保该输入的 validationRules 规则被检查为 true 或 false,然后使用检查结果更新有效键。我们还添加了 touched 属性,用于指示用户已触摸表单输入框,这将有助于在输入框被触摸时显示验证反馈。检查将在 changeHandler 方法中完成,如下所示:

changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
const updatedControls = {
...this.state.formControls
};
const updatedFormElement = {
...updatedControls[name]
};
updatedFormElement.value = value;
updatedFormElement.touched = true;
updatedFormElement.valid = validate(value, updatedFormElement.validationRules);
updatedControls[name] = updatedFormElement;
this.setState({
formControls: updatedControls
});
}
changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
const updatedControls = {
...this.state.formControls
};
const updatedFormElement = {
...updatedControls[name]
};
updatedFormElement.value = value;
updatedFormElement.touched = true;
updatedFormElement.valid = validate(value, updatedFormElement.validationRules);
updatedControls[name] = updatedFormElement;
this.setState({
formControls: updatedControls
});
}

有效等同于方法validate(value, prevState.formControls[name]).validationRules),我们将使用它来检查特定控件的有效状态是真还是假。

const validate = (value, rules) => {
let isValid = true;
for (let rule in rules) {
switch (rule) {
case 'minLength': isValid = isValid && minLengthValidator(value, rules[rule]); break;
default: isValid = true;
}
}
return isValid;
}
/**
* minLength Val
* @param value
* @param minLength
* @return
*/
const minLengthValidator = (value, minLength) => {
return value.length >= minLength;
}
export default validate;
view raw validation.js hosted with ❤ by GitHub
const validate = (value, rules) => {
let isValid = true;
for (let rule in rules) {
switch (rule) {
case 'minLength': isValid = isValid && minLengthValidator(value, rules[rule]); break;
default: isValid = true;
}
}
return isValid;
}
/**
* minLength Val
* @param value
* @param minLength
* @return
*/
const minLengthValidator = (value, minLength) => {
return value.length >= minLength;
}
export default validate;
view raw validation.js hosted with ❤ by GitHub

我将验证方法移至单独的类,然后将其导入。验证方法接受两个参数:值和规则。我们循环遍历规则并检查每个规则是否有效,如果有效则返回 true,如果无效则返回 false。

假设我们想在 name 上添加另一个验证,例如,我们希望 name 为必填项。我们需要做的就是更新 formControl 中的 name 验证规则,并在验证器类中编写相应的逻辑,如下所示

constructor() {
super();
this.state = {
formControls: {
name: {
value: ''.
placeholder: 'What is your name',
valid: false,
touched: false,
validationRules: {
minLength: 3,
isRequired: true //just added this
}
}
}
}
}
constructor() {
super();
this.state = {
formControls: {
name: {
value: ''.
placeholder: 'What is your name',
valid: false,
touched: false,
validationRules: {
minLength: 3,
isRequired: true //just added this
}
}
}
}
}

然后我们需要更新验证器类以适应所需的验证器。

const validate = (value, rules) => {
let isValid = true;
for (let rule in rules) {
switch (rule) {
case 'minLength': isValid = isValid && minLengthValidator(value, rules[rule]); break;
case 'isRequired': isValid = isValid && requiredValidator(value); break;
case 'isEmail': isValid = isValid && emailValidator(value); break;
default: isValid = true;
}
}
return isValid;
}
/**
* minLength Val
* @param value
* @param minLength
* @return
*/
const minLengthValidator = (value, minLength) => {
return value.length >= minLength;
}
/**
* Check to confirm that feild is required
*
* @param value
* @return
*/
const requiredValidator = value => {
return value.trim() !== '';
}
/**
* Email validation
*
* @param value
* @return
*/
const emailValidator = value => {
var re = /^(([^<>()\[\]\\.,;:\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,}))$/;
return re.test(String(value).toLowerCase());
}
export default validate;
const validate = (value, rules) => {
let isValid = true;
for (let rule in rules) {
switch (rule) {
case 'minLength': isValid = isValid && minLengthValidator(value, rules[rule]); break;
case 'isRequired': isValid = isValid && requiredValidator(value); break;
case 'isEmail': isValid = isValid && emailValidator(value); break;
default: isValid = true;
}
}
return isValid;
}
/**
* minLength Val
* @param value
* @param minLength
* @return
*/
const minLengthValidator = (value, minLength) => {
return value.length >= minLength;
}
/**
* Check to confirm that feild is required
*
* @param value
* @return
*/
const requiredValidator = value => {
return value.trim() !== '';
}
/**
* Email validation
*
* @param value
* @return
*/
const emailValidator = value => {
var re = /^(([^<>()\[\]\\.,;:\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,}))$/;
return re.test(String(value).toLowerCase());
}
export default validate;

我们创建了一个自定义的 TextInput,我们创建了一个 formControl,它有一个名为 name 的属性,其验证规则为 isRequired 和 minLength 为 3。下面是处理此问题的组件:

import React, { Component } from 'react';
import TextInput from './TextInput';
import validate from './validator';
class FormComponent extends Component {
constructor() {
super();
this.state = {
formControls: {
name: {
value: ''.
placeholder: 'What is your name',
valid: false,
touched: false,
validationRules: {
minLength: 3,
isRequired: true
}
}
}
}
}
changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
const updatedControls = {
...this.state.formControls
};
const updatedFormElement = {
...updatedControls[name]
};
updatedFormElement.value = value;
updatedFormElement.touched = true;
updatedFormElement.valid = validate(value, updatedFormElement.validationRules);
updatedControls[name] = updatedFormElement;
this.setState({
formControls: updatedControls
});
}
formSubmitHandler = () => {
console.dir(this.state.formControls);
}
render() {
return (
<div>
<TextInput name="name"
placeholder={this.state.formControls.name.placeholder}
value={this.state.formControls.name.value}
onChange={this.changeHandler}
/>
<button onClick={this.formSubmitHandler}> Submit </button>
</div>
);
}
}
import React, { Component } from 'react';
import TextInput from './TextInput';
import validate from './validator';
class FormComponent extends Component {
constructor() {
super();
this.state = {
formControls: {
name: {
value: ''.
placeholder: 'What is your name',
valid: false,
touched: false,
validationRules: {
minLength: 3,
isRequired: true
}
}
}
}
}
changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
const updatedControls = {
...this.state.formControls
};
const updatedFormElement = {
...updatedControls[name]
};
updatedFormElement.value = value;
updatedFormElement.touched = true;
updatedFormElement.valid = validate(value, updatedFormElement.validationRules);
updatedControls[name] = updatedFormElement;
this.setState({
formControls: updatedControls
});
}
formSubmitHandler = () => {
console.dir(this.state.formControls);
}
render() {
return (
<div>
<TextInput name="name"
placeholder={this.state.formControls.name.placeholder}
value={this.state.formControls.name.value}
onChange={this.changeHandler}
/>
<button onClick={this.formSubmitHandler}> Submit </button>
</div>
);
}
}

如果我们在填写 TextInput 后​​单击提交按钮,formSubmitHandler 将控制台 formControls 值如下所示

有效 = 真或假

好处是,我们不必等到用户点击提交后才能知道表单输入是否有效。由于它实际上存储在组件状态中,因此,我们可以使用它在用户输入时显示错误消息或反馈。我们甚至可以禁用提交按钮,直到验证通过。

显示错误反馈

为了能够在输入框上显示错误反馈,我们需要将该输入框的 touched 和 valid 属性作为 prop 传递给组件。我们将根据有效状态添加错误样式,并且仅在输入框被触摸时执行此操作。

render() {
return (
<TextInput name="name"
placeholder={this.state.formControls.name.placeholder}
value={this.state.formControls.name.value}
onChange={this.changeHandler}
touched={this.state.formControls.name.touched}
valid={this.state.formControls.name.valid}
/>
);
}
render() {
return (
<TextInput name="name"
placeholder={this.state.formControls.name.placeholder}
value={this.state.formControls.name.value}
onChange={this.changeHandler}
touched={this.state.formControls.name.touched}
valid={this.state.formControls.name.valid}
/>
);
}

我们还需要修改我们的 TextInput 组件以根据 props.valid 和 props.touched 的值显示样式。

import React from 'react';
const TextInput = props => {
let formControl = "form-control";
if (props.touched && !props.valid) {
formControl = 'form-control control-error';
}
return (
<div className="form-group">
<input type="text" className={formControl} {...props} />
</div>
);
}
export default TextInput;
import React from 'react';
const TextInput = props => {
let formControl = "form-control";
if (props.touched && !props.valid) {
formControl = 'form-control control-error';
}
return (
<div className="form-group">
<input type="text" className={formControl} {...props} />
</div>
);
}
export default TextInput;

请注意,您应该将 form-control 和 control-error 样式添加到 App.css 中。

.form-control {
width: 50%;
border: 1px solid #ccc;
padding: 10px;
}
.control-error {
border: 1px solid red;
}
view raw App.css hosted with ❤ by GitHub
.form-control {
width: 50%;
border: 1px solid #ccc;
padding: 10px;
}
.control-error {
border: 1px solid red;
}
view raw App.css hosted with ❤ by GitHub

如果您的 TextInput 无效并且已被触碰,您应该会看到如下截图。

如果表单无效,则禁用“提交”按钮

HTML 5 的按钮输入框有一个 disabled 属性,我们可以将 formControls 属性的有效状态等同于 disabled 属性。只要 formControls 无效即可。

<button onClick={this.formSubmitHandler}
disabled={!this.state.formControls.name.valid}
>
Submit
</button>
<button onClick={this.formSubmitHandler}
disabled={!this.state.formControls.name.valid}
>
Submit
</button>

如果我们只有一个表单控件,disabled={!this.state.formControls.name.valid} 可以正常工作。但如果我们需要处理多个表单控件,我们可以为状态设置一个新属性,用于跟踪整个 formControl 对象的有效性状态。因此,我们需要更新状态以适应这种情况。

constructor () {
super();
this.state = {
formIsValid: false, //we will use this to track the overall form validity
formControls: {
name: {
value: '',
valid: false,
validationRules: {
isRequired: true
},
placeholderText: 'Your name please',
touched: false
}
}
};
}
constructor () {
super();
this.state = {
formIsValid: false, //we will use this to track the overall form validity
formControls: {
name: {
value: '',
valid: false,
validationRules: {
isRequired: true
},
placeholderText: 'Your name please',
touched: false
}
}
};
}

我们需要更新 changeHandler 方法,以便我们可以循环遍历所有表单控件的有效状态,并且当有效时,将 formIsValid 状态更新为 true。

changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
const updatedControls = {
...this.state.formControls
};
const updatedFormElement = {
...updatedControls[name]
};
updatedFormElement.value = value;
updatedFormElement.touched = true;
updatedFormElement.valid = validate(value, updatedFormElement.validationRules);
updatedControls[name] = updatedFormElement;
let formIsValid = true;
for (let inputIdentifier in updatedControls) {
formIsValid = updatedControls[inputIdentifier].valid && formIsValid;
}
this.setState({
formControls: updatedControls,
formIsValid: formIsValid
});
}
changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
const updatedControls = {
...this.state.formControls
};
const updatedFormElement = {
...updatedControls[name]
};
updatedFormElement.value = value;
updatedFormElement.touched = true;
updatedFormElement.valid = validate(value, updatedFormElement.validationRules);
updatedControls[name] = updatedFormElement;
let formIsValid = true;
for (let inputIdentifier in updatedControls) {
formIsValid = updatedControls[inputIdentifier].valid && formIsValid;
}
this.setState({
formControls: updatedControls,
formIsValid: formIsValid
});
}

通过此设置,我们可以更轻松地将 disabled 属性设置为 formIsValid 状态,这将处理一个或多个表单对象。

<button onClick={this.formSubmitHandler}
disabled={!this.state.formIsValid}
>
Submit
</button>
<button onClick={this.formSubmitHandler}
disabled={!this.state.formIsValid}
>
Submit
</button>

考虑其他表单输入类型

TEXTAREA:文本区域、邮箱和密码的功能与文本输入类似。我们可以创建一个 TextArea 组件。

import React from 'react';
const TextArea = props => {
let formControl = "form-control";
if (props.touched && !props.valid) {
formControl = 'form-control control-error';
}
return (
<div className="form-group">
<textarea {...props} className={formControl} />
</div>
);
}
export default TextArea;
view raw TextArea.js hosted with ❤ by GitHub
import React from 'react';
const TextArea = props => {
let formControl = "form-control";
if (props.touched && !props.valid) {
formControl = 'form-control control-error';
}
return (
<div className="form-group">
<textarea {...props} className={formControl} />
</div>
);
}
export default TextArea;
view raw TextArea.js hosted with ❤ by GitHub

EMAIL:我们也可以像 TextInput 一样创建一个 Email 组件

import React from 'react';
const Email = props => {
let formControl = "form-control";
if (props.touched && !props.valid) {
formControl = 'form-control control-error';
}
return (
<div className="form-group">
<input type="email" className={formControl} {...props} />
</div>
);
}
export default Email;
view raw email.js hosted with ❤ by GitHub
import React from 'react';
const Email = props => {
let formControl = "form-control";
if (props.touched && !props.valid) {
formControl = 'form-control control-error';
}
return (
<div className="form-group">
<input type="email" className={formControl} {...props} />
</div>
);
}
export default Email;
view raw email.js hosted with ❤ by GitHub

PASSWORD:我们也可以像 TextInput 一样创建一个密码组件

import React from 'react';
const Password = props => {
let formControl = "form-control";
if (props.touched && !props.valid) {
formControl = 'form-control control-error';
}
return (
<div className="form-group">
<input type="password" className={formControl} {...props} />
</div>
);
}
export default Password;
view raw Password.js hosted with ❤ by GitHub
import React from 'react';
const Password = props => {
let formControl = "form-control";
if (props.touched && !props.valid) {
formControl = 'form-control control-error';
}
return (
<div className="form-group">
<input type="password" className={formControl} {...props} />
</div>
);
}
export default Password;
view raw Password.js hosted with ❤ by GitHub

电子邮件、文本区域和密码表单控件将看起来类似于文本输入表单输入

constructor() {
super();
this.state = {
formControls: {
age: {
value: ''.
placeholder: 'What is your age',
valid: false,
touched: false,
validationRules: {
minLength: 3,
isRequired: true
}
}
}
}
}
view raw form_control.js hosted with ❤ by GitHub
constructor() {
super();
this.state = {
formControls: {
age: {
value: ''.
placeholder: 'What is your age',
valid: false,
touched: false,
validationRules: {
minLength: 3,
isRequired: true
}
}
}
}
}
view raw form_control.js hosted with ❤ by GitHub

选择选项:选择选项表单控件与其他表单控件略有不同,因为我们必须适应选择选项。它如下所示

gender: {
value: '',
placeholder: 'What is your gender',
valid: false,
touched: false,
validationRules: {
isRequired: true,
},
options: [
{ value: 'male', displayValue: 'Male' },
{ value: 'female', displayValue: 'Female'}
]
}
gender: {
value: '',
placeholder: 'What is your gender',
valid: false,
touched: false,
validationRules: {
isRequired: true,
},
options: [
{ value: 'male', displayValue: 'Male' },
{ value: 'female', displayValue: 'Female'}
]
}

那么选择选项组件将如下所示

import React from 'react';
const Select = props => {
let formControl = "form-control";
if (props.touched && !props.valid) {
formControl = 'form-control control-error';
}
return (
<div className="form-group">
<select className={formControl} value={props.value} onChange={props.onChange} name={props.name}>
{props.options.map(option => (
<option value={option.value}>
{option.displayValue}
</option>
))}
</select>
</div>
);
}
export default Select;
view raw Select.js hosted with ❤ by GitHub
import React from 'react';
const Select = props => {
let formControl = "form-control";
if (props.touched && !props.valid) {
formControl = 'form-control control-error';
}
return (
<div className="form-group">
<select className={formControl} value={props.value} onChange={props.onChange} name={props.name}>
{props.options.map(option => (
<option value={option.value}>
{option.displayValue}
</option>
))}
</select>
</div>
);
}
export default Select;
view raw Select.js hosted with ❤ by GitHub

RADIO:单选按钮类似于选择按钮,因为它是所有可用选项中唯一一个可选的选项。表单控件类似于选择按钮的表单控件。单选按钮组件如下所示。

import React from 'react';
const Radio = props => {
let formControl = "form-control";
if (props.touched && !props.valid) {
formControl = 'form-control control-error';
}
return (
<div className="form-group">
{props.options.map(option => (
<div className="form-group" key={option.value}>
<label>{option.displayValue}</label>
<input type="radio"
name={props.name}
value={option.value}
onChange={props.onChange}
className={formControl}
/>
</div>
))}
</div>
);
}
export default Radio;
view raw Radio.js hosted with ❤ by GitHub
import React from 'react';
const Radio = props => {
let formControl = "form-control";
if (props.touched && !props.valid) {
formControl = 'form-control control-error';
}
return (
<div className="form-group">
{props.options.map(option => (
<div className="form-group" key={option.value}>
<label>{option.displayValue}</label>
<input type="radio"
name={props.name}
value={option.value}
onChange={props.onChange}
className={formControl}
/>
</div>
))}
</div>
);
}
export default Radio;
view raw Radio.js hosted with ❤ by GitHub

综上所述,假设我们想在一个表单控件中实现邮箱输入框、姓名(TextInput)、性别(Select Input)和单选框。以下是组件的示例:

import React, { Component } from 'react';
import './App.css';
import TextInput from './TextInput';
import validate from './validate';
import TextArea from './TextArea';
import Email from './Email';
import Select from './Select';
import Radio from './Radio';
class App extends Component {
constructor() {
super();
this.state = {
formIsValid: false,
formControls: {
name: {
value: '',
placeholder: 'What is your name',
valid: false,
validationRules: {
minLength: 4,
isRequired: true
},
touched: false
},
address: {
value: '',
placeholder: 'What is your address',
valid: false,
validationRules: {
minLength: 4,
isRequired: true
},
touched: false
},
my_email: {
value: '',
placeholder: 'What is your email',
valid: false,
validationRules: {
isRequired: true,
isEmail: true
},
touched: false
},
gender: {
value: '',
placeholder: 'What is your gender',
valid: false,
touched: false,
validationRules: {
isRequired: true,
},
options: [
{ value: 'male', displayValue: 'Male' },
{ value: 'female', displayValue: 'Female'}
]
},
my_radio: {
value: '',
placeholder: 'Are you a frontend developer',
valid: false,
touched: false,
validationRules: {
// isRequired: true,
},
options: [
{ value: 0, displayValue: 'No' },
{ value: 1, displayValue: 'Yes' }
]
}
}
}
}
changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
const updatedControls = {
...this.state.formControls
};
const updatedFormElement = {
...updatedControls[name]
};
updatedFormElement.value = value;
updatedFormElement.touched = true;
updatedFormElement.valid = validate(value, updatedFormElement.validationRules);
updatedControls[name] = updatedFormElement;
let formIsValid = true;
for (let inputIdentifier in updatedControls) {
formIsValid = updatedControls[inputIdentifier].valid && formIsValid;
}
this.setState({
formControls: updatedControls,
formIsValid: formIsValid
});
}
formSubmitHandler = () => {
const formData = {};
for (let formElementId in this.state.formControls) {
formData[formElementId] = this.state.formControls[formElementId].value;
}
console.dir(formData);
}
render() {
return (
<div className="App">
<TextInput name="name"
placeholder={this.state.formControls.name.placeholder}
value={this.state.formControls.name.value}
onChange={this.changeHandler}
touched={this.state.formControls.name.touched}
valid={this.state.formControls.name.valid}
/>
<TextArea name="address"
placeholder={this.state.formControls.address.placeholder}
value={this.state.formControls.address.value}
onChange={this.changeHandler}
touched={this.state.formControls.address.touched}
valid={this.state.formControls.address.valid}
/>
<Email name="my_email"
placeholder={this.state.formControls.my_email.placeholder}
value={this.state.formControls.my_email.value}
onChange={this.changeHandler}
touched={this.state.formControls.my_email.touched}
valid={this.state.formControls.my_email.valid}
/>
<Select name="gender"
value={this.state.formControls.gender.value}
onChange={this.changeHandler}
options={this.state.formControls.gender.options}
touched={this.state.formControls.gender.touched}
valid={this.state.formControls.gender.valid}
/>
<Radio name="my_radio"
value={this.state.formControls.my_radio.value}
onChange={this.changeHandler}
options={this.state.formControls.my_radio.options}
touched={this.state.formControls.my_radio.touched}
valid={this.state.formControls.my_radio.valid}
/>
<button onClick={this.formSubmitHandler}
disabled={! this.state.formIsValid}
>
Submit
</button>
</div>
);
}
}
export default App;
import React, { Component } from 'react';
import './App.css';
import TextInput from './TextInput';
import validate from './validate';
import TextArea from './TextArea';
import Email from './Email';
import Select from './Select';
import Radio from './Radio';
class App extends Component {
constructor() {
super();
this.state = {
formIsValid: false,
formControls: {
name: {
value: '',
placeholder: 'What is your name',
valid: false,
validationRules: {
minLength: 4,
isRequired: true
},
touched: false
},
address: {
value: '',
placeholder: 'What is your address',
valid: false,
validationRules: {
minLength: 4,
isRequired: true
},
touched: false
},
my_email: {
value: '',
placeholder: 'What is your email',
valid: false,
validationRules: {
isRequired: true,
isEmail: true
},
touched: false
},
gender: {
value: '',
placeholder: 'What is your gender',
valid: false,
touched: false,
validationRules: {
isRequired: true,
},
options: [
{ value: 'male', displayValue: 'Male' },
{ value: 'female', displayValue: 'Female'}
]
},
my_radio: {
value: '',
placeholder: 'Are you a frontend developer',
valid: false,
touched: false,
validationRules: {
// isRequired: true,
},
options: [
{ value: 0, displayValue: 'No' },
{ value: 1, displayValue: 'Yes' }
]
}
}
}
}
changeHandler = event => {
const name = event.target.name;
const value = event.target.value;
const updatedControls = {
...this.state.formControls
};
const updatedFormElement = {
...updatedControls[name]
};
updatedFormElement.value = value;
updatedFormElement.touched = true;
updatedFormElement.valid = validate(value, updatedFormElement.validationRules);
updatedControls[name] = updatedFormElement;
let formIsValid = true;
for (let inputIdentifier in updatedControls) {
formIsValid = updatedControls[inputIdentifier].valid && formIsValid;
}
this.setState({
formControls: updatedControls,
formIsValid: formIsValid
});
}
formSubmitHandler = () => {
const formData = {};
for (let formElementId in this.state.formControls) {
formData[formElementId] = this.state.formControls[formElementId].value;
}
console.dir(formData);
}
render() {
return (
<div className="App">
<TextInput name="name"
placeholder={this.state.formControls.name.placeholder}
value={this.state.formControls.name.value}
onChange={this.changeHandler}
touched={this.state.formControls.name.touched}
valid={this.state.formControls.name.valid}
/>
<TextArea name="address"
placeholder={this.state.formControls.address.placeholder}
value={this.state.formControls.address.value}
onChange={this.changeHandler}
touched={this.state.formControls.address.touched}
valid={this.state.formControls.address.valid}
/>
<Email name="my_email"
placeholder={this.state.formControls.my_email.placeholder}
value={this.state.formControls.my_email.value}
onChange={this.changeHandler}
touched={this.state.formControls.my_email.touched}
valid={this.state.formControls.my_email.valid}
/>
<Select name="gender"
value={this.state.formControls.gender.value}
onChange={this.changeHandler}
options={this.state.formControls.gender.options}
touched={this.state.formControls.gender.touched}
valid={this.state.formControls.gender.valid}
/>
<Radio name="my_radio"
value={this.state.formControls.my_radio.value}
onChange={this.changeHandler}
options={this.state.formControls.my_radio.options}
touched={this.state.formControls.my_radio.touched}
valid={this.state.formControls.my_radio.valid}
/>
<button onClick={this.formSubmitHandler}
disabled={! this.state.formIsValid}
>
Submit
</button>
</div>
);
}
}
export default App;

谢谢阅读。

文章来源:https://dev.to/abelagoi/the-complete-guide-to-forms-inreact-2c4o
PREV
使用超级令牌进行有效的会话管理
NEXT
如何创建生产 Docker 镜像