antd-form 学习笔记

AntD-Form 是基于 rc-form 来做了一层封装,我们看看它提供了哪些额外的功能

先来看看 Form

  • 首先按照惯例获取SizeContext,ConfigContext,主要获取Size,getPrefixCls,direction,form.requiredMark.
  • 然后依次来获取 className,mergedRequiredMark.
  • 创建formInstance,这个是在rc.useForm封装了一层,添加了scrollToField(),getFieldInstance(),getFieldInstance(),这个是获取 Field 的 ReactElement.
  • FormContext 这个跟 rc 的FormContext 不一样,虽然名字一样(很容易让人误导),这个主要是布局相关的一些信息,还有 Field 对于的 ReactElement.
  • 封装了onFinishFailed 方法,根据配置scrollToFirstError 会让第一个错误进入 viewport.
  • 最后套上SizeContextProvider,FormContext.Provider 里面放上rc-Form.

看看 FieldItem

FieldItem 是在rc-Field 基础上添加了一些额外的功能。它主要添加了label,require 标记,tooltip,对于 input,它还添加了errorlist,gethelp 等,还有就是label 与 input的布局,通过colspan,offset来控制一共 24 个格子。这个里面有两个大的分支,布局以及rc-field的功能。布局要不要由noStyle控制,rc-field的功能阉割由!hasName && !isRenderProps && !dependencies控制

if (!hasName && !isRenderProps && !dependencies) {
  return renderLayout(children) as JSX.Element;
}
  • 首先获取从ConfigContext中获取getPrefixCls,从antd.FormContext中获取formName,requireMark,创建FormItemContext这里面就一个方法updateItemErrors: (name: string, errors: string[], originName?: string) => void
  • 最终每个FieldItemField被封装成,如下的结构。FormItemLabellabel,requiredrequiredMark决定,colon也由它接管,由colon控制。同时还可以支持tooltip。这里面有两个分支,一个是Field,另一个是普通的控件,跟 form 无关,另一个是Field。判断条件是
  • FieldItem里面还有一个noStyle, 这个值是控制是否要显示label,error,设置这个值表示,这些东西由父级接管了。
if (!hasName && !isRenderProps && !dependencies) {
  return renderLayout(children) as JSX.Element;
}
<Row>
  <FormItemLabel />
  <FormItemInput>{children}</FormItemInput>
</Row>
  • FieldItemInput 它其实包含inputDom, errorListDom, extraDom三部分,inputDom 如下,errorList 也如下。 ErrorList有点怪,功能很简单,就是把 error 挨个显示出来,但是用了一个 useCacheErrors,这个方法很简单,但是触发的过程确实好复杂。有好几层异步,还不明白为什么搞这么复杂。这段代码应该是打补丁打出来的。
const inputDom = (
  <div className={`${baseClassName}-control-input`}>
    <div className={`${baseClassName}-control-input-content`}>{children}</div>
    {icon}
  </div>
);
const errorListDom = (
  <FormItemPrefixContext.Provider value={{ prefixCls, status }}>
    <ErrorList
      errors={errors}
      help={help}
      onDomErrorVisibleChange={onDomErrorVisibleChange}
    />
  </FormItemPrefixContext.Provider>
);

再聊聊几个参数组合使用的禁忌

  • shouldUpdatedependencies不可以同时使用。
  • 如果Item里面的 children 是数组,则不能使用 name。
  • 如果 children 是 renderProps,则必须跟 shouldUpdate 或者 dependencies 组合使用。同时 Field 不能使用 name,因为 renderProps 其实是一个可变的逻辑,它里面的内容才是 Field。
  • 如果设置了 dependencies, 要么指定名字,要么使用 renderProps。

聊聊 dependencies vs shouldUpdate,

  • 共同点,这两个都是依据一定的条件决定当前的 Field 要不要刷新。
  • 不同点,dependencies,一般用于 validation, 也就是 upstream 的 Field 更新了,当前的 Field 要不要刷新,这个主要是用来激发验证的逻辑。如果当前的 Field 里面需要根据 upstream 里面的值来决定显示哪些 Field,那么这种情况下推荐用 shouldUpdate。因为,如果我们调用FormInstance.setFieldsValue() 时,这些隐藏的 Field 不会被刷新。只要用 shouldUpdate 才会。参考下面的例子。
    BugHere
<Item name='gender'
                    label='Gender'
                    rules={[{required:true}]}
                >
                    <Select
                        placeholder="Select a option and change input text above"
                        onChange={onGenderChange}
                        allowClear
                    >
                        <Option value='male'>Male</Option>
                        <Option value='female'>Female</Option>
                        <Option value='other'>Other</Option>
                    </Select>
                </Item>
                <Item dependencies={['gender']}
                    //shouldUpdate={(prev,cur)=>prev.gender!=cur.gender}
                    noStyle
                >
                    {({getFieldValue})=>{
                        const gender = getFieldValue(['gender']);
                        return gender === 'other'?(
                            <Item name="customizeGender"
                                label="Customize Gender"
                                rules={[{required:true}]}
                                >
                                    <Input/>
                            </Item>
                        ):null;
                    }}
                </Item>
posted @ 2021-07-21 14:54  kongshu  阅读(935)  评论(0编辑  收藏  举报