高阶组件版表单组件设计思路进阶
表单组件要求实现数据收集、校验、提交等特性,可通过高阶组件扩展
高阶组件给表单组件传递一个input组件包装函数接管其输入事件并统一管理表单数据
高阶组件给表单组件传递一个校验函数使其具备数据校验功能
Input.js文件内容如下:
import React, { Component } from 'react'
const Input = (props) => {
return <input {...props} />
}
export default class CustomizeInput extends Component {
constructor(props) {
super(props);
}
render() {
const { value = "", ...otherProps } = this.props;
return (
<div style={{padding: '10px'}}>
<Input style={{outline: 'none'}} value={value} {...otherProps} />
</div>
)
}
}
1.实现一个简单的表单功能:
MyRCForm.js文件内容如下:
import React, { Component } from 'react'
import Input from '../components/Input';
class MyRCForm extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: ""
}
}
nameChange = (e) => {
this.setState({
username: e.target.value
})
}
passwordChange = (e) => {
this.setState({
password: e.target.value
})
}
submit = () => {
const { username, password } = this.state;
console.log("syta", username, password); // sy-log
}
render() {
const { username, password } = this.state;
return (
<div>
<h3>MyRCForm</h3>
<Input
placeholder="Username"
value={username}
onChange={this.nameChange}
/>
<Input
placeholder="Password"
value={password}
onChange={this.passwordChange}
/>
<button onClick={this.submit}>submit</button>
</div>
)
}
}
export default MyRCForm
2.使用rc-form的高阶组件createForm:
MyRCForm.js文件内容如下:
import React, { Component } from 'react'
import Input from '../components/Input';
import { createForm } from 'rc-form'; // 安装rc-form:npm install rc-form
const nameRules = {required: true, message: "请输入姓名!"};
const passwordRules = {required: true, message: "请输入密码!"};
@createForm()
class MyRCForm extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
const { setFieldsValue } = this.props.form;
setFieldsValue({
username: "default"
});
}
submit = () => {
const { getFieldsValue, getFieldValue } = this.props.form;
console.log("syta", getFieldsValue(), getFieldValue("username")); // sy-log
}
render() {
console.log("props", this.props);
const { getFieldDecorator } = this.props.form;
return (
<div>
<h3>MyRCForm</h3>
{getFieldDecorator("username", {rules: [nameRules]})(<Input
placeholder="Username"
/>)}
{getFieldDecorator("password", {rules: [passwordRules]})(<Input
placeholder="Password"
/>)}
<button onClick={this.submit}>submit</button>
</div>
)
}
}
export default MyRCForm
打印结果如下:
3.自定义一个高阶组件createForm:
MyRCForm.js文件内容如下:
import React, { Component } from 'react';
import Input from '../components/Input';
import { createForm } from '../components/my-rc-form/index';
const nameRules = {required: true, message: "请输入姓名!"};
const passwordRules = {required: true, message: "请输入密码!"};
@createForm
class MyRCForm extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
const { setFieldsValue } = this.props.form;
setFieldsValue({
username: "李明",
password: "123"
});
}
submit = () => {
const { getFieldsValue, getFieldValue, validateFields } = this.props.form;
console.log("syta", getFieldsValue(), getFieldValue("username")); // sy-log
validateFields((err, vals) => {
if(err) {
console.log("失败", err)
}else {
console.log("成功", vals)
}
})
}
render() {
console.log("props", this.props);
const { getFieldDecorator } = this.props.form;
return (
<div>
<h3>MyRCForm</h3>
{getFieldDecorator("username", {rules: [nameRules]})(<Input
placeholder="Username"
/>)}
{getFieldDecorator("password", {rules: [passwordRules]})(<Input
placeholder="Password"
/>)}
<button onClick={this.submit}>submit</button>
</div>
)
}
}
export default MyRCForm
components/my-rc-form/index.js文件内容如下:
import React, { Component } from 'react'
export function createForm(Cmp) {
return class extends Component {
constructor(props) {
super(props);
this.state = {}
this.options = {}
}
getFieldsValue = () => {
return {...this.state};
}
getFieldValue = (name) => {
return this.state[name];
}
setFieldsValue = (newStore) => {
this.setState(newStore)
}
handleChange = (e) => {
const { name, value } = e.target;
this.setState({
[name]: value
}, () => {
console.log("state", this.state);
})
}
getFieldDecorator = (fieldName, option) => InputCmp => {
this.options[fieldName] = option;
return React.cloneElement(InputCmp, {
name: fieldName,
value: this.state[fieldName] || "",
onChange: this.handleChange
});
}
validateFields = (callback) => {
let err = [];
for(let fieldName in this.options) {
if(!this.state[fieldName]) {
err.push({
[fieldName]: "err"
})
}
}
if(err.length === 0) {
callback(null, {...this.state});
}else {
callback(err, {...this.state});
}
}
getForm = () => {
return {
getFieldsValue: this.getFieldsValue,
getFieldValue: this.getFieldValue,
setFieldsValue: this.setFieldsValue,
getFieldDecorator: this.getFieldDecorator,
validateFields: this.validateFields
}
}
render() {
const form = this.getForm();
return (
<div>
<Cmp {...this.props} form={form}/>
</div>
)
}
}
}
打印结果如下:
注意:antd3 的设计有个问题,就是局部变化会引起整体变化,即每次输入框的值发生变化的时候,会重新渲染页面,比较消耗性能,不过 antd4 改进了这个问题。