共计 2941 个字符,预计需要花费 8 分钟才能阅读完成。
前言
通过模拟 rc-form 的实现思路,能够学习一下 hoc 的应用场景。
裸露 createForm() 函数
通过 createForm 函数,返回一个组件。该组件拓展了咱们的一些办法。
export function createForm(Cmp) { | |
return class extends Component {getFieldDecorator = () => {} | |
getFieldsValue = () => {} | |
getFieldValue = () => {} | |
setFieldValue = () => {} | |
validateFields = () => {} | |
form = () => { | |
return { | |
getFieldDecorator: this.getFieldDecorator, | |
getFieldValue: this.getFieldValue, | |
getFieldsValue: this.getFieldsValue, | |
setFieldValue: this.setFieldValue, | |
validateFields: this.validateFields, | |
} | |
} | |
render() {const form = getForm() | |
return <Cmp {...this.props} form={form} /> | |
} | |
} | |
} |
实现 getFieldDecorator
应用办法
<div> | |
{getFieldDecorator('username', {rules: { require: true, message: '请输出用户名'})(<input placeholder="请输出用户名" />)} | |
</div> |
能够看出,该函数接管两个参数,第一个是字段名,第二个是它的规定。又接着返回了一个接管一个组件的函数,最终返回一个加工后的组件。当初咱们开始简略实现一下。
constructor(){ | |
// ... | |
this.state = {} | |
this.options = {}} |
getFieldDecorator = (fieldName, option) => InputCmp => { | |
// 保留数据和选项 | |
if (this.state[fieldName] === undefined) this.setState({[fieldName]: '' }) | |
this.options[fieldName] = option | |
// 返回一个解决后的组件 | |
return React.cloneElement(InputCmp, { | |
name: fieldName, | |
value: this.state[fieldName], | |
onChange: this.handleChange, | |
}) | |
} |
定义 handleChange 事件
handleChange = (e) => {const { name, value} = e.target | |
this.setState({[name]: value }) | |
} |
实现 getFieldValue
间接把 state 的数据返回即可
getFieldsValue = () => {return {...this.state} | |
} |
实现 getFieldsValue
通过传进来的名字,返回对应的数据
getFieldValue = name => {return this.state[name] | |
} |
实现 setFieldValue
间接将传进来的数据合并起来即可
setFieldValue = state => {this.setState(state) | |
} |
实现 validateFields
该办法接管一个回调函数,通过遍历 options 的规定,在判断相应的值,返回谬误数据以及 state 的数据
validateFields = callback => {const err = [] | |
for (let fieldName in this.options) {const rules = this.options[fieldName]?.rules | |
const value = this.state[fieldName] | |
if(rules && rules.require && rules.message && !value) { | |
err.push({[fieldName]: rules.message | |
}) | |
} | |
} | |
// 判断 err 是否有数据 | |
if (err.length === 0) {callback(null, { ...this.state}) | |
} else {callback(err, { ...this.state}) | |
} | |
} |
最终代码
import React, {Component} from 'react' | |
export function createForm(Cmp) { | |
return class extends Component {constructor(props) {super(props) | |
this.state = {} | |
this.options = {}} | |
handleChange = e => {const { name, value} = e.target | |
this.setState({[name]: value }) | |
} | |
validateFields = callback => {const err = [] | |
for (let fieldName in this.options) {const rules = this.options[fieldName]?.rules | |
if (rules && rules.require && rules.message && !this.state[fieldName]) { | |
err.push({[fieldName]: rules.message, | |
}) | |
} | |
} | |
if (err.length === 0) {callback(null, { ...this.state}) | |
} else {callback(err, { ...this.state}) | |
} | |
} | |
getFieldDecorator = (fieldName, option) => InputCmp => {this.options[fieldName] = option | |
if (this.state[fieldName] === undefined) this.setState({[fieldName]: '' }) | |
return React.cloneElement(InputCmp, { | |
name: fieldName, | |
value: this.state[fieldName], | |
onChange: this.handleChange, | |
}) | |
} | |
getFieldValue = name => {return this.state[name] | |
} | |
getFieldsValue = () => {return { ...this.state} | |
} | |
setFieldValue = state => {this.setState(state) | |
} | |
getForm = () => { | |
return { | |
getFieldDecorator: this.getFieldDecorator, | |
getFieldValue: this.getFieldValue, | |
getFieldsValue: this.getFieldsValue, | |
setFieldValue: this.setFieldValue, | |
validateFields: this.validateFields, | |
} | |
} | |
render() {const form = this.getForm() | |
return <Cmp {...this.props} form={form} /> | |
} | |
} | |
} |
正文完