前言
通过模仿 rc-form 的实现思路,可以学习一下 hoc 的使用场景。
通过 createForm 函数,返回一个组件。该组件拓展了我们的一些方法。
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
| 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
使用方法
1 2 3
| <div> {getFieldDecorator('username', {rules: { require: true, message: '请输入用户名' })(<input placeholder="请输入用户名" />)} </div>
|
可以看出,该函数接收两个参数,第一个是字段名,第二个是它的规则。又接着返回了一个接收一个组件的函数,最终返回一个加工后的组件。现在我们开始简单实现一下。
1 2 3 4 5
| constructor(){ this.state = {} this.options = {} }
|
1 2 3 4 5 6 7 8 9 10 11
| 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 事件
1 2 3 4
| handleChange = (e) => { const { name, value } = e.target this.setState({ [name]: value }) }
|
实现 getFieldValue
直接把 state 的数据返回即可
1 2 3
| getFieldsValue = () => { return {...this.state} }
|
实现 getFieldsValue
通过传进来的名字,返回对应的数据
1 2 3
| getFieldValue = name => { return this.state[name] }
|
实现 setFieldValue
直接将传进来的数据合并起来即可
1 2 3
| setFieldValue = state => { this.setState(state) }
|
实现 validateFields
该方法接收一个回调函数,通过遍历options的规则,在判断相应的值,返回错误数据以及state的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 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 }) } } if (err.length === 0) { callback(null, { ...this.state }) } else { callback(err, { ...this.state }) } }
|
最终代码
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
| 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} /> } } }
|