关于react.js:hoc实现表单组件的设计思路

7次阅读

共计 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} />
    }
  }
}
正文完
 0