配置
从(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-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
| module.exports = function override(config, env) {
config = injectBabelPlugin( ['import', { libraryName: 'antd', libraryDirectory: 'es', style: 'css' }], config, ) config = injectBabelPlugin( ['@babel/plugin-proposal-decorators', { "legacy": true }], config, ) return config }
|
创建并使用装饰器
创建从conponents/MForm.js
和MFormCreate.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";
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 => { const rules = this.options[field].rules; 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); };
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