中后台领域中,数据录入是一个重要的场景,在该场景中form(表单)扮演一个重要的角色。表单中涉及到大量的交互,主要表如今如下几个方面:javascript
咱们从一个简单登陆页的例子提及,来总结form是如何使用的。html
咱们直接使用react的受控组件模式,对每一个输入项的状态保存在组件state中,经过onChange事件,实时更新值。java
import React from 'react';
class FormDemo extends React.Component {
state = {
username: '',
password: '',
usernameMsg: '',
passwordMsg: '',
};
onChangeName = e => {
const value = e.target.value;
this.setState({
username: value,
usernameMsg: !value ? '请填写' : ‘’, // 非空校验
});
};
onChangePassword = e => {
const value = e.target.value;
this.setState({
password: value,
passwordMsg: !value ? '请填写' : ‘', // 非空校验
});
};
handleSubmit = () => {
// post data
};
render() {
// 获取数据和错误信息
const { username, password, usernameMsg, passwordMsg } = this.state;
return (
<form>
<input value={username} onChange={this.onChangeName} />
<span>{usernameMsg}</span>
<input value={password} onChange={this.onChangePassword} />
<span>{passwordMsg}</span>
<button type="submit" onClick={this.handleSubmit}>提交</button>
</form>
);
}
}
复制代码
这种方法百分之百使用原生的方式实现:表单的每个field都对应于组件内的state的一个值,每个field有一个对应的错误信息用于展现错误,每一个field的值经过onChange事件进行改变。这种方式实现简单明了,可是当field较多时,须要大量的重复这种value + onChange
的模式。因此,须要一种方式,将重复的工做抽象出来。react
rc-form内部使用fieldsStore对全部field进行集中式管理,当数据改变时,重绘整个form。json
import { createForm } from 'rc-form';
class Form extends React.Component {
submit = () => {
this.props.form.validateFields((error, value) => {
console.log(error, value);
});
}
render() {
let usernameErrors, passwordErrors;
const { getFieldProps, getFieldError } = this.props.form;
return (
<div>
<input {...getFieldProps('username', {rules: [{required: true}]})}/>
{(usernameErrors = getFieldError('password')) ? errors.join(',') : null}
<input {...getFieldProps('password', {rules: [{required: true}]})}/>
{(passwordErrors = getFieldError('password')) ? errors.join(',') : null}
<button onClick={this.submit}>submit</button>
</div>
);
}
}
export createForm()(Form);
复制代码
createForm()
使用高阶组件的方式,对form注入了一些额外的方法与属性。getFieldProps
方法用于把field注册到fieldsStore里面,fieldsStore对field的变化进行追踪。能够看出相比第一种方式,rc-form把状态与UI进行分层,咱们省去了对每个field的状态管理,不用再去为每个field进行状态进行value + onChange
的重复。antd
在以上过程当中,咱们完成了登陆的功能逻辑,可是还缺乏表单的样式。表单样式包括两部分:表单的总体样式和每一个field的样式。因而咱们抽象出Form和FormItem用于承载样式,因而就有了antdForm。antd form就是在rc-form的基础上增长了form布局演化而来。咱们也能够经过自定义Form和FormItem + rc-form的形式去实现form的布局。架构
代码以下:app
<Form onSubmit={(values) => { submit(values) }}>
<Form.Item label="姓名">
{getFieldDecorator('name')(<Input />)}
</Form.Item>
<Form.Item label="密码">
{getFieldDecorator('password')(<Input.Password />)}
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">提交</Button>
</Form.Item>
</Form>
复制代码
antd-form的架构以下: 异步
在使用antd-form过程当中,遇到如下问题:分布式
uform很好的解决了使用form过程当中遇到的各类问题,以uform 0.4.x版本为例(1.x版本发生了很大的变化)。
UForm 主要分为三层结构:
uform采用分布式状态管理,数据同步靠根组件广播须要更新子组件重绘,根组件只负责消息分发。这样能够作到只更新单个组件。uform支持json schema和集中性的反作用管理。
使用uform代码以下:
const Schema = {
user: {
type: 'object',
properties: {
username: {
type: 'string',
title: '用户名',
required: true,
},
password: {
type: 'string',
title: '密码',
required: true,
},
}
}
const defaultValue = {
user: {
username: '',
password: ''
}
}
<SchemaForm
labelCol={8}
wrapperCol={16}
schema={Schema}
defaultValue={defaultValue}
onSubmit={this.onSubmit}
>
</SchemaForm>
复制代码
使用uform,咱们能够先定义form的schema和默认值,以后交给uform进行渲染。 uform能够方便的处理多种场景,如联动等。