【React】React模拟Antd的表单组件

Posted by ARTROY on 2019-10-17

配置

从(1)(2)二选一方法即可。

(1)执行 npm run eject(二选一)

eject(弹射)命令做的事情,就是把潜藏在 react- scripts 中的一系列技术栈配置都“弹射”到应用的顶层,然后我们就可以研究这些配置细节了,而且可以更灵活地定制应用的配置,不过特别注意,整个过程是不可逆的。

(2)执行react-app-rewired(二选一)

安装react-app-rewired取代react-scripts,可以扩展 webpack的配置。由于新的 react-app-rewired@2.x 版本的关系,你还需要安装customize-cra
所以当下执行

1
2
3
// npm install react-app-rewired@2.0.2-next.0 babel-plugin-import --save-dev
npm install react-app-rewired --save-dev
npm install customize-cra --save-dev

(3)安装高阶组件装饰器

执行npm install --save-dev babel-plugin-transform-decorators-legacy,ES7装饰器可用于简化高阶组件写法。

撸代码

如使用方法(1)+(3),则配置package.json即可:

1
2
3
4
5
6
7
8
9
"babel": {
"presets": [
"react-app"
],
// 添加此处
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }]
]
},

如使用方法(2)+(3),则先配置package.json,再在当前项目的根目录创建config-overrides.js文件。
// 修改package.json

1
2
3
4
5
6
7
8
9
10
11
12
"scripts": {
// 原来代码
// "start": "react-scripts start",
// "build": "react-scripts build",
// "test": "react-scripts test",
// "eject": "react-scripts eject"
// 修改后代码
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject"
},

// 创建config-overrides.js并设置(类似Antd也能如此设置),但是得先执行 npm install antd --save

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* config-overrides.js */
module.exports = function override(config, env) {
// do stuff with the webpack config...

// Antd
config = injectBabelPlugin(
['import', { libraryName: 'antd', libraryDirectory: 'es', style: 'css' }],
config, )
config = injectBabelPlugin(
['@babel/plugin-proposal-decorators', { "legacy": true }],
config,
)
return config
}

创建并使用装饰器

创建从conponents/MForm.jsMFormCreate.js,并修改APP.js文件。
// MForm.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import React from "react";
import MFormCreate from './MFormCreate';

@MFormCreate
class MForm extends React.Component {
onSubmit = () => {
console.log("submit");
// 校验所有项
this.props.validate((isValid, data) => {
if (isValid) {
//提交登录
console.log("登录:", data);
// 后续登录逻辑
} else {
alert("校验失败");
}
});
};

render() {
const { getFieldDecorator } = this.props;
return (
<div>
{getFieldDecorator("uname", {
rules: [{ required: true, message: "用户名必填" }]
})(<input type="text" value='123' ></input>)}

{getFieldDecorator("pwd", {
rules: [{ required: true, message: "密码必填" }]
})(<input type="password" value='123'></input>)}

<button onClick={this.onSubmit}>登录</button>
</div>
);
}
}

export default MForm;

// MFormCreate.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import React from "react";
// import { Input, Button } from "antd";

// 创建一个高阶组件:扩展现有表单,事件处理、数据收集、校验
export default function MFormCreate(Comp) {
return class extends React.Component {
constructor(props) {
super(props);

this.options = {};
this.state = {};
}

handleChange = e => {
const { name, value } = e.target;

this.setState({ [name]: value }, () => {
// 确保值发生变化再校验
this.validateField(name);
});
};

// 单项校验
validateField = field => {
// 1. 获取校验规则
const rules = this.options[field].rules;
// 任意一项失败则返回false
const ret = !rules.some(rule => {
if (rule.required) {
if (!this.state[field]) {
//校验失败
this.setState({
[field + "Message"]: rule.message
});
return true;
}
}
});

if (ret) { // 校验成功
this.setState({
[field + "Message"]: ""
});
}
return ret;
};

// 校验所有字段
validate = cb => {
const rets = Object.keys(this.options).map(field =>
this.validateField(field)
);

const ret = rets.every(v => v == true);
cb(ret, this.state);
};

// 创建input包装器
getFieldDecorator = (field, option) => {
// 保存当前输入项配置
this.options[field] = option;
return InputComp => (
<div>
{React.cloneElement(InputComp, {
name: field,
value: this.state[field] || "",
onChange: this.handleChange
})}
{/* 校验错误信息 */}
{this.state[field+'Message'] && (
<p style={{color:'red'}}>{this.state[field+'Message']}</p>
)}
</div>
);
};

render() {
return <Comp getFieldDecorator={this.getFieldDecorator} validate={this.validate} />;
}
};
}

// APP.js

1
2
3
4
5
6
7
8
9
10
11
12
13
import React from 'react';
import MForm from './components/MForm';
import './App.css';

function App() {
return (
<div className="App">
<MForm/>
</div>
);
}

export default App;
注意:装饰器必须作用于class


支付宝打赏 微信打赏

欣赏此文,打赏一下



-->