antd4-form设计[源码解读]

2,121 阅读1分钟

form表单大概有几个重要的组件

Form 主要是负责提交信息
Field 每一个输入选项包裹-- 主要是 给 包裹对象增加额外的处理
useForm 通过自定义组件来处理所有逻辑
Form 和 下面的children 可以通过 context 传递数据

Form -- 最外层的表单

  • 处理sumbit方法
  • 使用自定义hook-useForm
  • 创建Provider 传递 context
const [ formInstance ] = useForm(form)
formInstance.registerCallback({
    onFinish,
    onFinishFailed
})
return (
    <form
        onSubmit={event => {
            event.preventDefault()
            formInstance.submit()
        }}
    >
        <FieldContext.Provider value = { formInstance }>//把逻辑传递下去
            { children }
        </FieldContext.Provider>
    </form>
)

Field

  • 赋予表单的功能,以input为例,需要赋予value 属性,onChanges事件 因为赋予功能,需要用到React.cloneElement这个api
  • 要考虑到当获取的数据变化同样UI要更新,所有在onChange改变数据之后,forceUpdate一下
render() {
    const { children } = this.props;
    const returnChildNode = React.cloneElement(children, this.getControlled())
    return returnChildNode
}

getControlled(){
    const { getFieldValue,setFieldsValue } = this.context;
    const { name } = this.props
    return {
        value: getFieldValue(name),
        onChange: (event)=>{
            let newVal = event.target.value;
            setFieldsValue({
                [name]: newVal
            })
        }
    }
}

onStoreChange(){
    this.forceUpdate()
}

最后就是所有的逻辑控制层,自定义hook useForm

  • 设置 store 存储数据 和 组件的实例
  • 设置一些方法 getFieldsValue setFieldsValue submit、validate等
  • 最后定义useForm

定义数据

class FormStore {
    constructor(){
        this.store = {} // { "username":"lilei","password":"123" }各种表单项
        this.fieldEntities = []
        this.callbacks = {}
    }

定义方法

getFieldValue = (name) => {
    return this.store[name]
}
getFiledsValue(){
    return this.store
}

setFieldsValue = (newStore) => {
    this.store = {
        ...this.store,
        ...newStore
    }
    console.log("this.fieldEntities",this.fieldEntities)
    this.fieldEntities.forEach( entity => {
        const { name } = entity.props;
        Object.keys(newStore).map( key => {
            if(key === name){
                entity.onStoreChange()
            }
        } )

    } )
    
}

定义useForm

export default function useForm(form) {
    const formRef = useRef()
    console.log(formRef.current)
    //特别重要不然就不是维护同一个 FormStore
    if(!formRef.current){
        if(form){
            formRef.current = form
        }else{
            const formStore = new FormStore();
            formRef.current = formStore.getForm()
        }
    }
    return [formRef.current]
}

总结:useForm 是通过useRef() 的 current 来构建单例模式,Form->Field->Input 数据采用 context, 组件调用useForm逻辑,先把组件注册进去,然后在useForm 里 调用 组件的方法。