首页
/ antd Form 表单组件完全指南:数据域管理、校验与动态表单实战(基于 ant-design 组件库)

antd Form 表单组件完全指南:数据域管理、校验与动态表单实战(基于 ant-design 组件库)

2026-09-07 20:48:53作者:彭桢灵Jeremy

本指南以 ant-design 仓库中 Form 官方中文文档 为骨架,结合 组件源码表单实例实现示例代码 展开。你将系统掌握 Form 的「何时使用」场景、Form / Form.Item / Form.List / Form.Provider 四大 API 的完整配置、四个 Hooks(useFormuseFormInstanceuseWatchForm.Item.useStatus)的用法,以及 dependenciesshouldUpdatenormalize、动态增删字段、滚动到错误等高频实战问题的原理与解法。

何时使用

Form 是 antd 的高性能表单控件,自带数据域管理,涵盖数据录入、校验以及对应样式。典型使用场景有两个:

  • 用于创建一个实体或收集信息(登录、注册、发布、设置等场景)。
  • 需要对输入的数据类型进行校验时(必填、格式、长度、正则、跨字段联动等)。

快速上手:受控数据域的第一个表单

Form 最核心的设计是接管name 字段包裹的子控件:自动注入 value(或 valuePropName 指定的属性)与 onChange(或 trigger 指定的属性),从而把所有字段数据收敛到自身的 store 中统一管理。完整示例见 basic demo,核心代码如下:

import { Button, Checkbox, Form, Input } from 'antd';

const onFinish = (values) => {
  console.log('Success:', values);
};

const App = () => (
  <Form
    name="basic"
    labelCol={{ span: 8 }}
    wrapperCol={{ span: 16 }}
    initialValues={{ remember: true }}
    onFinish={onFinish}
    onFinishFailed={(errorInfo) => console.log('Failed:', errorInfo)}
    autoComplete="off"
  >
    <Form.Item
      label="Username"
      name="username"
      rules={[{ required: true, message: 'Please input your username!' }]}
    >
      <Input />
    </Form.Item>

    <Form.Item name="remember" valuePropName="checked" label={null}>
      <Checkbox>Remember me</Checkbox>
    </Form.Item>

    <Form.Item label={null}>
      <Button type="primary" htmlType="submit">Submit</Button>
    </Form.Item>
  </Form>
);

提交时数据满足校验,触发 onFinish(values);校验失败则触发 onFinishFailed。注意 Checkbox 的真实值属性是 checked 而非 value,因此必须配合 valuePropName="checked"(其原理参见后文 FAQ)。一旦被 Form.Item 接管,数据流将遵循三条硬性规则:

  1. 不再需要也不应该用子控件 onChange 做数据收集同步(仍可继续监听,但同步交给 Form)。需要全局监听值变化时用 Form 的 onValuesChange
  2. 不能用控件的 value / defaultValue 设置表单域初始值,默认值应通过 Form 的 initialValues 设置。且 initialValues 不能被 setState 动态更新——动态改值必须用 form.setFieldsValue
  3. 不要用 setState 维护受控字段,统一用 form.setFieldsValue 驱动。

Form:顶层表单组件

Form 同时承担「数据 store」与「布局容器」两个职责。从 Form.tsx 源码可见,其默认 layouthorizontal,渲染时通过 DisabledContextProviderSizeContext.ProviderVariantContext.Provider 分别向下下发 disabledsizevariant,因此这些配置对树内所有 antd 控件「一键生效」。

API 一览

下表列出行内 FormProps 定义的完整可配置项(其中标注「全局配置」列的属性,还可以通过 ConfigProvider 的 form 命名空间统一设置):

参数 说明 类型 默认值 版本 全局配置
classNames 自定义组件内部各语义化结构的 class,支持对象或函数 Record<SemanticDOM, string> | (info: { props }) => Record<SemanticDOM, string> - 6.0.0 6.0.0
colon 配置 Form.Item 的 colon 默认值,表示是否显示 label 后的冒号(仅 layouthorizontal 时有效) boolean true 4.18.0
disabled 设置表单组件禁用,仅对 antd 组件有效 boolean false 4.21.0 ×
component 设置 Form 渲染元素,为 false 则不创建 DOM 节点 ComponentType | false form - ×
fields 通过状态管理(如 redux)控制表单字段,非强需求不推荐 FieldData[] - - ×
form Form.useForm() 创建的 form 控制实例,不提供时自动创建 FormInstance - - ×
feedbackIcons Form.Item 有 hasFeedback 时自定义反馈图标 FeedbackIcons - 5.9.0 ×
initialValues 表单默认值,仅初始化和重置时生效 object - - ×
labelAlign label 文本对齐方式 left | right right - 6.4.0
labelWrap label 文本是否可换行 boolean false 4.18.0 ×
labelCol label 标签布局,同 <Col>{ span: 3, offset: 12 }{ sm: { span: 3, offset: 12 } } object - - ×
layout 表单布局 horizontal | vertical | inline horizontal - ×
name 表单名称,会作为字段 id 前缀 string - - ×
preserve 字段被删除时保留字段值,可用 getFieldsValue(true) 获取 boolean true 4.4.0 ×
requiredMark 必选样式,可切换为必选或可选展示样式;此为 Form 级配置,Form.Item 无法单独配置 boolean | 'optional' | ((label, { required }) => ReactNode) true renderProps: 5.9.0 4.8.0
scrollToFirstError 提交失败自动滚动到第一个错误字段 boolean | Options | { focus: boolean } false focus: 5.24.0 5.2.0
size 字段组件尺寸(仅限 antd 组件) small | medium | large - - ×
styles 自定义各语义化结构的行内 style,支持对象或函数 Record<SemanticDOM, CSSProperties> | (info: { props }) => Record<...> - - 6.0.0
tooltip 配置提示属性 TooltipProps & { icon?: ReactNode } - 6.3.0 6.3.0
validateMessages 验证提示模板(详见下一节) ValidateMessages - - 4.0.0
validateTrigger 统一设置字段触发验证的时机 string | string[] onChange 4.3.0 ×
variant 表单内控件变体 outlined | borderless | filled | underlined outlined 5.13.0(underlined: 5.24.0) 5.19.0
wrapperCol 输入控件布局,用法同 labelCol object - - ×
onFieldsChange 字段更新时触发 function(changedFields, allFields) - - ×
onFinish 提交且校验成功后触发 function(values) - - ×
onFinishFailed 提交且校验失败后触发 function({ values, errorFields, outOfDate }) - - ×
onValuesChange 字段值更新时触发 function(changedValues, allValues) - - ×
clearOnDestroy 表单卸载时清空表单值 boolean false 5.18.0 ×

此外还支持原生 <form>onSubmit 外的所有属性(如 autoCompleteid 等)。在 Form.tsxFormProps 中可见 prefixClsrootClassName 等扩展字段;源码中 useComponentConfig('form') 会从 ConfigProvider 读取 requiredMarkcolontooltiplabelAlign 等默认值并做合并,这正是「全局配置列」生效的机制。

默认校验消息 validateMessages

Form 为验证提供了默认错误提示信息(位于 locale/en_US.ts,含 requiredtypes.*string.*number.*array.*pattern 等全部模板)。可通过 validateMessages 覆盖模板,最常见的是配置国际化提示:

const validateMessages = {
  required: "'${name}' 是必选字段",
  // ...
};

<Form validateMessages={validateMessages} />;

也可以通过 ConfigProvider 做全局统一配置:

const validateMessages = {
  required: "'${name}' 是必选字段",
  // ...
};

<ConfigProvider form={{ validateMessages }}>
  <Form />
</ConfigProvider>;

从源码看,Form 渲染时会将 ConfigProvider 下发的 validateMessages 注入 FormProvider(见 Form.tsx),实现全树共享。

Form.Item:字段绑定、校验与布局的单元

Form.Item 用于数据双向绑定、校验、布局,是日常使用最频繁的子组件。主要 API 如下:

参数 说明 类型 默认值 版本
colon 配合 label 使用,是否显示 label 后的冒号 boolean true -
dependencies 设置依赖字段(见下节) NamePath[] - -
extra 额外提示信息,与错误信息可同时出现 ReactNode - -
getValueFromEvent 设置如何把 event 的值转换成字段值 (..args) => any - -
getValueProps 为子元素添加额外属性 (value) => Record<string, any> - 4.2.0
hasFeedback 配合 validateStatus 展示校验状态图标;可传 { icons: FeedbackIcons } boolean | { icons: FeedbackIcons } false icons: 5.9.0
help 提示信息,不设置时按校验规则自动生成 ReactNode - -
hidden 是否隐藏字段(仍收集与校验) boolean false 4.4.0
htmlFor 设置子元素 label 的 htmlFor string - -
initialValue 子元素默认值,与 Form 的 initialValues 冲突时以 Form 为准 string - 4.2.0
label label 文本;不需要 label 又需与冒号对齐时设为 null ReactNode - null: 5.22.0
labelAlign 标签文本对齐方式 left | right right -
labelCol label 布局,同 <Col>;可通过 Form labelCol 统一设置(不作用于嵌套 Item),两者同时设置时以 Item 为准 object - -
messageVariables 默认验证字段的信息替换 Record<string, string> - 4.7.0
name 字段名,支持数组 NamePath - -
normalize 组件获取值后先转换再放入 Form;不支持异步 (value, prevValue, prevValues) => any - -
noStyle true 时不带样式,作为纯字段控件;无自身 validateStatus 时会继承父级 Form.Item boolean false -
preserve 字段被删除时保留字段值 boolean true 4.4.0
required 必填样式;不设置则根据校验规则自动生成,设 false 可禁用该样式 boolean - -
rules 校验规则(见 Rule Rule[] - -
shouldUpdate 自定义字段更新逻辑(见下节) boolean | (prevValue, curValue) => boolean false -
tooltip 配置提示信息 ReactNode | (TooltipProps & { icon?: ReactNode }) - 4.7.0
trigger 收集字段值变更的时机 string onChange -
validateFirst 某规则失败后是否停止后续规则;parallel 时并行校验 boolean | 'parallel' false parallel: 4.5.0
validateDebounce 校验防抖延迟毫秒数 number - 5.9.0
validateStatus 校验状态:success | warning | error | validating;不设置则自动生成 string - -
validateTrigger 设置字段校验时机 string | string[] onChange -
valuePropName 子节点值属性名;Switch、Checkbox 应为 checked。是 getValueProps 的封装,自定义 getValueProps 后会失效 string value -
wrapperCol 输入控件布局,用法同 labelCol,优先级规则同 labelCol object - -
layout 表单项布局 horizontal | vertical - 5.18.0

注意 colonrequiredMarksizedisabledvariant 等更倾向在 Form 层统一设置,会通过 Context 下发到所有 Item 的控件上。

dependencies:字段间校验联动

当一个字段设置了 dependencies,它所依赖的字段更新时,该字段会自动触发更新与校验。典型场景是注册表单的「密码 / 确认密码」:「确认密码」依赖「密码」,修改密码后自动重跑确认逻辑。可运行示例见 form-dependencies demo

<Form.Item
  label="Confirm Password"
  name="password2"
  dependencies={['password']}
  rules={[
    { required: true },
    ({ getFieldValue }) => ({
      validator(_, value) {
        if (!value || getFieldValue('password') === value) {
          return Promise.resolve();
        }
        return Promise.reject(new Error('The new password that you entered do not match!'));
      },
    }),
  ]}
>
  <Input />
</Form.Item>

注意:dependencies 不应与 shouldUpdate 混用,否则会带来更新逻辑混乱。此外它主要响应「用户交互触发」的字段更新;对于 setFieldsValue 触发的变化(如切换字段选项),应改用 shouldUpdateuseWatch(见 FAQ)。

FeedbackIcons:自定义校验反馈图标

当需要自定义 hasFeedback 的图标时使用:

type FeedbackIcons = (info: { status: ValidateStatus; errors: ReactNode; warnings: ReactNode }) =>
  Record<ValidateStatus, ReactNode>;

shouldUpdate:精确控制渲染范围

Form 采用增量更新,只刷新被修改字段相关的组件以优化性能。大多数场景配合 dependencies 即可,但当「修改某字段后出现新字段选项」或「希望表单任意变化都让某区域重新渲染」时,用 shouldUpdate 改写 Form.Item 的更新逻辑。相关 issue:#34500

shouldUpdatetrue 时,Form 任意变化都会触发该 Form.Item 重渲染,且包裹的子组件必须由函数返回,否则不生效:

<Form.Item shouldUpdate>
  {() => {
    return <pre>{JSON.stringify(form.getFieldsValue(), null, 2)}</pre>;
  }}
</Form.Item>

shouldUpdate 为函数时,每次数值更新都会携带新旧值供比较,非常适合「按值决定是否渲染额外字段」:

<Form.Item shouldUpdate={(prevValues, curValues) => prevValues.additional !== curValues.additional}>
  {() => {
    return (
      <Form.Item name="other">
        <Input />
      </Form.Item>
    );
  }}
</Form.Item>

具体用法可分别参考 inline-login democontrol-hooks demo(后者用 shouldUpdategender === 'other' 时渲染额外输入项,其中 getFieldValue 由 renderProps 参数解构提供)。

messageVariables:替换校验信息中的变量

可通过 messageVariables 修改默认验证信息中 ${label}${name} 等占位符的取值:

<Form>
  <Form.Item
    messageVariables={{ another: 'good' }}
    label="user"
    rules={[{ required: true, message: '${another} is required' }]}
  >
    <Input />
  </Form.Item>
  <Form.Item
    messageVariables={{ label: 'good' }}
    label={<span>user</span>}
    rules={[{ required: true, message: '${label} is required' }]}
  >
    <Input />
  </Form.Item>
</Form>

自 5.20.2 起,若希望保留 ${} 不被转译,用 \${} 跳过:

{ required: true, message: '${label} is convert, \\${label} is not convert' }
// 渲染结果:good is convert, ${label} is not convert

Form.List:动态增减与数组化管理

Form.List 为字段提供数组化管理,例如「多乘客」「多成员」列表。API 如下:

参数 说明 类型 默认值 版本
children 渲染函数 (fields: Field[], operation: { add, remove, move }, meta: { errors }) => ReactNode - -
initialValue 子元素默认值,与 Form initialValues 冲突时以 Form 为准 any[] - 4.9.0
name 字段名,支持数组。List 本身也是字段,getFieldsValue() 默认返回其下所有值 NamePath - -
rules 校验规则,仅支持自定义规则,需配合 Form.ErrorList 使用 { validator, message }[] - 4.7.0

基础结构:

<Form.List name="names">
  {(fields) =>
    fields.map((field) => (
      <Form.Item {...field}>
        <Input />
      </Form.Item>
    ))
  }
</Form.List>

注意:Form.List 下的字段不应各自配置 initialValue,应始终通过 Form.List 的 initialValue 或 Form 的 initialValues 配置。完整动态示例见 dynamic-form-item demo:它展示了通过 rules 校验 List 至少 2 项、fields.map 渲染输入行、add() 在尾部追加、add('The head item', 0) 指定插入位置、remove(field.name) 删除,以及用 <Form.ErrorList errors={errors} /> 展示 List 级错误。更复杂的动态嵌套字段、拖拽排序与无样式纯字段场景,可分别参考 dynamic-form-items demodynamic-form-items-drag-sorting demodynamic-form-items-no-style demo

operation:List 操作函数

参数 说明 类型 默认值 版本
add 新增表单项 (defaultValue?: any, insertIndex?: number) => void insertIndex 4.6.0
move 移动表单项 (from: number, to: number) => void - -
remove 删除表单项 (index: number | number[]) => void number[] 4.5.0

Form.ErrorList:错误展示组件

4.7.0 新增,仅限配合 Form.List 的 rules 使用(参见 dynamic-form-item demoerrors 的展示方式):

参数 说明 类型 默认值
errors 错误列表 ReactNode[] -

Form.Provider:多表单联动

其下设置 name 的多个 Form 更新时,自动触发对应事件(示例见 form-context demo):

参数 说明 类型 默认值
onFormChange 子表单字段更新时触发 function(formName: string, info: { changedFields, forms }) -
onFormFinish 子表单提交时触发 function(formName: string, info: { values, forms }) -
<Form.Provider
  onFormFinish={(name) => {
    if (name === 'form1') {
      // Do something...
    }
  }}
>
  <Form name="form1">...</Form>
  <Form name="form2">...</Form>
</Form.Provider>

FormInstance:命令式实例方法

Form.useForm() 返回的实例承载所有数据读写与校验操作。在 hooks/useForm.ts 中可看到它基于 @rc-component/formrcForm 扩展出 scrollToFieldfocusFieldgetFieldInstance 等方法(scrollToField 先取字段 DOM,再调用 scroll-into-view-if-neededfocus: true 时滚动成功后聚焦)。完整方法如下:

名称 说明 类型 版本
getFieldError 获取指定字段的错误信息 (name: NamePath) => string[] -
getFieldInstance 获取字段实例 (name: NamePath) => any 4.4.0
getFieldsError 获取一组字段错误,返回数组 (nameList?: NamePath[]) => FieldError[] -
getFieldsValue 获取一组字段值,按结构返回;true 时返回含未注册字段的全部值 GetFieldsValue -
getFieldValue 获取指定字段值 (name: NamePath) => any -
isFieldsTouched 检查一组字段是否被操作过,allTouched: true 时要求全部被操作 (nameList?, allTouched?) => boolean -
isFieldTouched 检查字段是否被操作过 (name: NamePath) => boolean -
isFieldValidating 检查字段是否正在校验 (name: NamePath) => boolean -
resetFields 重置字段到 initialValues (fields?: NamePath[]) => void -
scrollToField 滚动到字段位置,可带 { focus: boolean } 聚焦 (name, options?) => void focus: 5.24.0
setFields 设置一组字段状态 (fields: FieldData[]) => void -
setFieldValue 设置单个字段值并重置其错误信息;不希望传入对象被修改请先克隆 (name, value) => void 4.22.0
setFieldsValue 设置字段值并重置错误;只想改 Form.List 中单项请用 setFieldValue (values) => void -
submit 提交表单,等同于点击 submit 按钮 () => void -
validateFields 触发表单验证;recursive 时递归校验所有包含路径 (nameList?, config?) => Promise -

validateFields 的配置与返回

export interface ValidateConfig {
  // 5.5.0 新增。仅校验内容而不将错误信息展示到 UI 上。
  validateOnly?: boolean;
  // 5.9.0 新增。对 nameList 及其子路径递归校验。
  recursive?: boolean;
  // 5.11.0 新增。校验 dirty(touched + validated)字段,方便只校验用户操作过的字段。
  dirty?: boolean;
}

返回示例:

validateFields()
  .then((values) => {
    /*
    values:
      {
        username: 'username',
        password: 'password',
      }
    */
  })
  .catch((errorInfo) => {
    /*
    errorInfo:
      {
        values: { username: 'username', password: 'password' },
        errorFields: [{ name: ['password'], errors: ['Please input your Password!'] }],
        outOfDate: false,
      }
    */
  });

Hooks:命令式能力的四个入口

Form.useForm

type Form.useForm = (): [FormInstance];

创建 Form 实例,用于管理所有数据状态;配合 <Form form={form}> 使用。典型调用见 control-hooks demosetFieldsValueresetFields、提交/重置/填充联动)。组件复合结构由 index.tsx 挂载:Form.Item / Form.List / Form.ErrorList / Form.Provider / Form.useForm / Form.useFormInstance / Form.useWatch 均为静态成员。

Form.useFormInstance

type Form.useFormInstance = (): FormInstance;

4.20.0 新增。在嵌套子组件中获取当前上下文 Form 实例,避免逐层透传 form

const Sub = () => {
  const form = Form.useFormInstance();
  return <Button onClick={() => form.setFieldsValue({})} />;
};

export default () => {
  const [form] = Form.useForm();
  return (
    <Form form={form}>
      <Sub />
    </Form>
  );
};

Form.useWatch

type Form.useWatch = (
  namePath: NamePath | ((selector: (values: Store) => any)),
  formInstance?: FormInstance | WatchOptions,
): Value;

5.12.0 新增 selector。用于直接响应式获取字段值,可与 useSWR 等数据请求联动,降低手动维护成本:

const Demo = () => {
  const [form] = Form.useForm();
  const userName = Form.useWatch('username', form);

  const { data: options } = useSWR(`/api/user/${userName}`, fetcher);

  return (
    <Form form={form}>
      <Form.Item name="username">
        <AutoComplete options={options} />
      </Form.Item>
    </Form>
  );
};

如果组件被包裹在 Form.Item 内部,可省略第二个参数,useWatch 会自动向上寻找最近 Form 实例。它默认只监听已注册字段,监听非注册字段需显式 preserve: true

const age = Form.useWatch('age', { form, preserve: true });

Form.Item.useStatus

type Form.Item.useStatus = (): { status: ValidateStatus | undefined; errors: ReactNode[]; warnings: ReactNode[] };

4.22.0 新增,5.4.0 补充 errorswarnings。用于自定义控件内感知当前 Form.Item 的校验状态(上层无 Form.Item 时 statusundefined):

const CustomInput = ({ value, onChange }) => {
  const { status, errors } = Form.Item.useStatus();
  return (
    <input
      value={value}
      onChange={onChange}
      className={`custom-input-${status}`}
      placeholder={(errors.length && errors[0]) || ''}
    />
  );
};

export default () => (
  <Form>
    <Form.Item name="username">
      <CustomInput />
    </Form.Item>
  </Form>
);

与其他取值方式的分工

Form 只对变更的 Field 刷新,避免整树重渲染的性能损耗,因此在 render 阶段无法通过 form.getFieldsValue 实时取到最新值。四类取值手段各有适用场景:

  • useWatch:特定字段的响应式访问,供当前组件 render/effect 直接消费。
  • Field.renderProps:仅更新需要更新的部分,渲染性能最优。
  • onValuesChange:当前组件不消费字段值时,将数据抛出,避免组件更新。
  • Form.Item.useStatus:只关心校验状态与错误/警告文案,如自定义输入框的边框与提示。

关键接口与类型

NamePath

string | number | (string | number)[],用于定位字段路径,如 'username'['user', 'age']

GetFieldsValue 重载

  • getFieldsValue(nameList?: true | NamePath[], filterFunc?: FilterFunc)
    • 不传 nameList:返回所有注册字段(含 List 下所有值)。
    • true:返回 store 中所有值(含未注册字段,例如 setFieldsValue 设置的、尚无对应 Item 的值)。
    • 传数组:返回规定路径的值,注意嵌套数组写法:
// 单个路径
form.getFieldsValue([['user', 'age']]);

// 多个路径
form.getFieldsValue([
  ['user', 'age'],
  ['preset', 'account'],
]);
  • getFieldsValue({ filter?: FilterFunc }):按过滤函数取值。

FilterFunc

type FilterFunc = (meta: { touched: boolean; validating: boolean }) => boolean;

可用于只取被用户修改过的字段值等场景。

FieldData

名称 说明 类型
errors 错误信息 string[]
warnings 警告信息 string[]
name 字段名称 NamePath[]
touched 是否被用户操作过 boolean
validating 是否正在校验 boolean
value 字段值 any

Rule 校验规则

Rule 支持 object 配置,也支持 function 动态获取 Form 数据:type Rule = RuleConfig | ((form: FormInstance) => RuleConfig)。各配置项:

名称 说明 类型 版本
defaultField 仅在 type: 'array' 时有效,指定数组元素校验规则 rule -
enum 是否匹配枚举中的值(需 type: 'enum' any[] -
fields 仅在 type: 'array' | 'object' 时有效,指定子元素校验规则 Record<string, rule> -
len string 为长度、number 为确定值、array 为长度 number -
max 需设置 type:string 最大长度 / number 最大值 / array 最大长度 number -
message 错误信息,不设置时按模板自动生成 string | ReactElement -
min 需设置 type,语义同 max number -
pattern 正则匹配 RegExp -
required 是否必选 boolean -
transform 校验前把值转换为目标值 (value) => any -
type 常见 string | number | boolean | url | email | tel string -
validateTrigger 验证时机,必须是 Form.Item validateTrigger 的子集 string | string[] -
validator 自定义校验,返回 Promise (rule, value) => Promise -
warningOnly 仅警告,不阻塞提交 boolean 4.17.0
whitespace 仅含空格视为不通过,仅在 type: 'string' 生效 boolean -

warningOnly 与动态校验可分别参考 warning-only demodynamic-rule demovalidator 的 Promise 用法见 register demo

WatchOptions

名称 说明 类型 默认值 版本
form 指定 Form 实例 FormInstance 当前 context 中的 Form 5.4.0
preserve 是否监视无对应 Form.Item 的字段 boolean false 5.4.0

Semantic DOM 与主题变量

Form 支持以 classNames / styles 精确控制 rootlabelcontenthelphelpItemextra 等语义化节点(见 Form.tsxFormSemanticType 定义),实际结构与示例见 _semantic.tsx,风格化用法见 style-class demo。组件级主题 Token 可参考 component-token demo

FAQ:高频问题与底层原理

1. Segmented 为什么不能被 Form disabled 禁用? Segmented 设计上是数据展示类而非表单控件类组件,行为更接近 Tabs,因此不受 Form 的 disabled 控制。讨论见 #54749

2. Switch、Checkbox 为什么绑定不上数据? Form.Item 默认绑定 value,而它们真实值属性是 checked,改用 valuePropName

<Form.Item name="fieldA" valuePropName="checked">
  <Switch />
</Form.Item>

3. name 为数组时的转换规则? 按顺序填充路径;当存在数字且 store 中没有该字段时自动转数组,因此需要数字作为 key 时应写成字符串,如 ['1', 'name']

4. 为何在 Modal 中调用 form 控制台报错("Instance created by useForm is not connect to any Form element")? 调用时 Modal 尚未初始化、form 未关联任何 Form。给 Modal 设置 forceRender 预渲染即可。

5. 为什么 Form.Item 下子组件 defaultValue 不生效? 设置 name 后子组件转为受控模式,defaultValue 自然失效,应通过 Form 的 initialValues 设置默认值。

6. 为什么第一次调用 ref 的 Form 为空? ref 仅在节点被加载后才被赋值,这是 React 的标准机制。

7. 为什么 resetFields 会重新 mount 组件? resetFields 会重置整个 Field,子组件随之重新 mount,从而清除自定义组件内部的副作用(异步数据、本地状态等)。

8. Form 的 initialValues 与 Item 的 initialValue 区别? 优先使用 Form 的 initialValues,仅在动态字段场景使用 Item 的 initialValue。默认值优先级:Form initialValues 最高 > Field initialValue;多个同 name Item 均设 initialValue 时该值不生效。

9. 为什么 getFieldsValue 初次渲染拿不到值? 它默认只返回已收集(已渲染注册)的字段数据;初次渲染 Form.Item 尚未挂载,需用 getFieldsValue(true) 获取全部数据。

10. 为什么 setFieldsValue 设为 undefined 时有的组件不重置为空? React 中值从确定值变为 undefined 意味着从受控转为非受控,展示值不会重置(Form store 内的值实际已变)。用带默认值的 HOC 保持受控:

const MyInput = ({ value = '', ...rest }) => <input value={value} {...rest} />;

<Form.Item name="my">
  <MyInput />
</Form.Item>;

11. 为什么设置 rulesonFieldsChange 触发三次? 字段状态除值外还包括校验态,变化过程为:Trigger value change → Rule validating → Rule validated,因此 isFieldValidating 会经历 false → true → false

12. 为什么 Form.List 不支持 label、还需用 ErrorList? Form.List 是 renderProps,内部样式自由,预设 label/error 节点难以配合;需要 antd 样式 label 时请用外层 Form.Item 包裹。

13. 为什么 dependencies 对 Form.List 下的字段无效? 依赖路径必须包含 Form.List 本身的 name,如:

<Form.List name="users">
  {(fields) =>
    fields.map((field) => (
      <React.Fragment key={field.key}>
        <Form.Item name={[field.name, 'name']} {...someRest1} />
        <Form.Item name={[field.name, 'age']} {...someRest1} />
      </React.Fragment>
    ))
  }
</Form.List>

此时依赖写法是 ['users', 0, 'name']

14. 为什么 normalize 不能是异步方法? React 中异步更新会导致受控组件交互异常:onChange 触发后值不会立即回写,组件呈「假死」状态。需要异步变更请用自定义组件内部实现异步状态。

15. scrollToFirstErrorscrollToField 失效?

  • 使用了自定义控件:自 5.17.0 起滚动优先使用控件转发的 ref 元素,请优先把 ref 转发给真正的表单元素;滚动依赖元素上的 id,自定义控件未把 id 赋到正确元素会失效(相关 issue:#28370#27994)。
  • 页面内多个表单且 name 重复:滚动可能定位到另一表单的同名项,需给各 Form 设置不同 name

16. 为什么不直接用 ref 绑定滚动元素? 自定义组件不支持 ref 时 Form 拿不到真实 DOM,而用 Class 包装调用 findDOMNode 在 React Strict Mode 下会告警,因此改用 id 定位元素。

17. setFieldsValue 不会触发 onFieldsChange / onValuesChange 是的,change 事件仅由用户交互触发,以防在 change 回调内调用 setFieldsValue 造成死循环;组件内消费请用 useWatchField.renderProps

18. 为什么 dependencies 不响应 setFieldsValue 触发的更新? dependencies 面向用户交互触发的字段间校验联动;需要按 setFieldsValue 后的值渲染内容或切换选项时用 shouldUpdateuseWatch

19. 为什么 Form.Item 嵌套子组件后不更新表单值? Form.Item 只向「直接子元素」注入 value/onChange,被包裹后属性无法穿透:

{/* 不会生效 */}
<Form.Item name="input">
  <div>
    <h3>I am a wrapped Input</h3>
    <Input />
  </div>
</Form.Item>

改为 HOC 自定义组件形式:

const MyInput = (props) => (
  <div>
    <h3>I am a wrapped Input</h3>
    <Input {...props} />
  </div>
);

<Form.Item name="input">
  <MyInput />
</Form.Item>;

20. 为什么点击 label 会更改组件状态? label 使用原生 HTML label 包裹控件以实现点击聚焦,这是提升可访问性的标准行为。若确实需要解除,可设置 htmlFor={null}

- <Form.Item name="switch" label="Switch">
+ <Form.Item name="switch" label="Switch" htmlFor={null}>
    <Switch />
  </Form.Item>

延伸阅读

想进一步把 Form 用「活」,可以依次深入仓库内示例与源码:

以上需求都建立在同一个底层能力之上:Form 把「数据、校验、布局」收敛为一份受控状态。理解了 FormInstance 与增量更新的关系,再配合 dependencies / shouldUpdate / useWatch 三种联动手段,即可在几乎所有复杂场景下写出高性能、易维护的表单代码。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391