前言
通过模拟 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} /> } }}