hoc实现表单组件的设计思路

前言 通过模仿 rc-form 的实现思路,可以学习一下 hoc 的使用场景。
暴露 createForm() 函数 通过 createForm 函数,返回一个组件。该组件拓展了我们的一些方法。

export function createForm(Cmp) { return class extends Component { getFieldDecorator = () => {}getFieldsValue = https://www.it610.com/article/() => {}getFieldValue = https://www.it610.com/article/() => {}setFieldValue = https://www.it610.com/article/() => {}validateFields = () => {}form = () => { return { getFieldDecorator: this.getFieldDecorator, getFieldValue: this.getFieldValue, getFieldsValue: this.getFieldsValue, setFieldValue: this.setFieldValue, validateFields: this.validateFields, } }render() { const form = getForm() return } } }

实现 getFieldDecorator 使用方法
{getFieldDecorator('username', {rules: { require: true, message: '请输入用户名' })()}

可以看出,该函数接收两个参数,第一个是字段名,第二个是它的规则。又接着返回了一个接收一个组件的函数,最终返回一个加工后的组件。现在我们开始简单实现一下。
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 = https://www.it610.com/article/() => { return {...this.state} }

实现 getFieldsValue 【hoc实现表单组件的设计思路】通过传进来的名字,返回对应的数据
getFieldValue = https://www.it610.com/article/name => { return this.state[name] }

实现 setFieldValue 直接将传进来的数据合并起来即可
setFieldValue = https://www.it610.com/article/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 = https://www.it610.com/article/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 = https://www.it610.com/article/name => { return this.state[name] }getFieldsValue = https://www.it610.com/article/() => { return { ...this.state } }setFieldValue = https://www.it610.com/article/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 } } }

    推荐阅读