当前位置: 首页 > news >正文

手写Antd的form组件源码

Ant Design 的表单组件 Form 是一个功能丰富的表单管理工具,它提供了表单的创建、验证、提交等核心功能。以下是其源码的详细解析和完整代码结构。

1. 源码位置

  • 官方仓库地址:https://github.com/ant-design/ant-design
  • Form 组件路径:
    • 主要文件:components/form/Form.tsx
    • 表单项:components/form/FormItem.tsx
    • 表单上下文:components/form/context.tsx
    • 表单 Hook:components/form/useForm.ts

2. 核心模块结构

2.1 入口文件:components/form/index.tsx

import React from 'react'; 
import Form from './Form'; 
export default Form;

这是对外暴露的入口点。

2.2 Form 组件定义(components/form/Form.tsx

import React, { forwardRef } from 'react'; 
import useSubscribe from './useSubscribe';import useForm from './useForm'; 
import FormContext from './context';import FormItem from './FormItem'; 
const InternalForm = forwardRef((props, ref) => {const [form] = useForm(); 
const { children } = props; 
return ( 
<FormContext.Provider value={form}> 
<form {...props}>{children}</form> 
</FormContext.Provider> );}); 
const Form = InternalForm; 
Form.Item = FormItem; 
export default Form;
功能说明:
  • 使用 forwardRef 支持 ref 转发。
  • 使用 useForm 创建表单实例。
  • 使用 FormContext.Provider 提供全局表单状态。
  • Form.Item 是子组件,用于包裹输入控件(如 InputSelect 等)。

2.2.1. Form.Item = FormItem;

Form.Item = FormItem; 是一种在 React 组件中为组件添加静态属性的写法,用于将 FormItem 作为 Form 组件的一个子组件暴露出去。这种写法常见于 Ant Design 这类 UI 框架中,使得开发者可以通过 Form.Item 的方式来使用表单项组件。

语法解释

Form.Item = FormItem;

这行代码的意思是:

  • 将 FormItem 组件赋值给 Form.Item,使其成为 Form 的一个“静态属性”。
  • 这样你就可以在 JSX 中像这样使用它:

<Form> <Form.Item label="用户名" name="username"> <Input /> </Form.Item> </Form>

为什么这么写?
  1. 命名空间管理

    • 把相关组件组织在一起,形成一种“父子结构”的命名空间,便于管理和使用。
    • 类似于 Table.ColumnTabs.TabPane 等写法。
  2. 提高可读性和一致性

    • 使用 Form.Item 而不是单独引入 FormItem,可以增强组件之间的语义关联。
    • 在大型项目或 UI 库中保持统一风格。
  3. 避免额外导入

    • 不需要再写:

      import FormItem from 'antd/lib/form/FormItem';

    • 而只需从 Form 上访问即可。
 示例:
// Form.tsx
const Form = forwardRef((props, ref) => {return <form>{props.children}</form>;
});Form.Item = FormItem;export default Form;
// FormItem.tsx
const FormItem = ({ label, name, children }) => {// 实现字段绑定、验证等逻辑return (<div className="form-item"><label>{label}</label>{children}</div>);
};export default FormItem;
完整结构 错误示例(不推荐)

如果你不用这种方式而是这样写:

import FormItem from './FormItem'; 
// 使用时 
<FormItem label="用户名" name="username">...</FormItem>

虽然也能工作,但会破坏组件的层级结构和封装性,不利于维护和 API 设计

2.3 表单项组件:components/form/FormItem.tsx

import React, { useEffect } from 'react';import useField from './useField'; 
import FormContext from './context'; 
const FormItem = ({ name, rules = [], children }) => { 
const form = React.useContext(FormContext); 
const field = useField(name, { rules }); 
useEffect(() => { 
form.registerField(field); 
}, []); 
return React.cloneElement(children, { 
value: field.value, 
onChange: (e) => field.onChange(e.target.value), 
}); 
}; 
export default FormItem;
功能说明:
  • 使用 React.cloneElement 将字段值和变更事件绑定到子组件。
  • 使用 useField 管理字段的状态和验证规则。
  • 注册字段到表单实例中。

2.4 表单 Hook:components/form/useForm.ts

import React from 'react'; 
import FormStore from './store'; 
function useForm() { 
const store = React.useMemo(() => new FormStore(), []);return [store]; 
} 
export default useForm

useForm;

功能说明:
  • 创建并返回一个 FormStore 实例。
  • 使用 useMemo 避免重复创建实例。

2.5 表单存储类:components/form/store.js

class FormStore {constructor() {this.fields = {};this.callbacks = {};}registerField(field) {this.fields[field.name] = field;}getFieldValue(name) {return this.fields[name]?.value;}setFieldsValue(values) {Object.keys(values).forEach(name => {if (this.fields[name]) {this.fields[name].setValue(values[name]);}});}validateFields() {const errors = {};Object.values(this.fields).forEach(field => {const error = field.validate();if (error) {errors[field.name] = error;}});return Object.keys(errors).length ? errors : null;}submit() {const errors = this.validateFields();if (!errors) {const values = Object.entries(this.fields).reduce((acc, [name, field]) => {acc[name] = field.value;return acc;}, {});this.callbacks.onFinish?.(values);} else {this.callbacks.onFinishFailed?.({ values: {}, errorFields: errors });}}setCallbacks(callbacks) {this.callbacks = callbacks;}
}export default FormStore;
功能说明:
  • registerField: 注册字段。
  • getFieldValue: 获取字段值。
  • setFieldsValue: 设置字段值。
  • validateFields: 触发表单验证。
  • submit: 提交表单。
  • setCallbacks: 设置回调函数(如 onFinishonFinishFailed)。

 2.6 字段状态管理的核心 Hook components/form/useField.ts

import React from 'react';
import warning from 'warning';type Store = Record<string, any>;
type Rule = { required?: boolean; message?: string };interface FieldConfig {name: string;rules?: Rule[];
}function useField(name: string, config: FieldConfig) {const [value, setValue] = React.useState('');const [error, setError] = React.useState('');// 注册到 Form 实例中const form = React.useContext(FormContext);React.useEffect(() => {form.registerField({ name, validate });}, []);// 设置值const handleChange = (e) => {const newValue = e.target.value;setValue(newValue);form.setFieldValue(name, newValue);};// 验证规则const validate = () => {const { rules = [] } = config;for (const rule of rules) {if (rule.required && !value) {setError(rule.message || `${name} is required`);return rule.message || `${name} is required`;}}setError('');return null;};return {value,error,onChange: handleChange,validate,};
}

2.7 表单上下文:components/form/context.js

import React from 'react';const FormContext = React.createContext(null); 
export default FormContext;

提供全局表单实例,供 FormItem 使用。 

3. 完整使用示例

import React from 'react';
import Form from './Form';
import FormItem from './FormItem';
import Input from '../input/Input';const DemoForm = () => {const [form] = Form.useForm();const onFinish = (values) => {console.log('Success:', values);};const onFinishFailed = (errorInfo) => {console.log('Failed:', errorInfo);};return (<Form form={form} onFinish={onFinish} onFinishFailed={onFinishFailed}><FormItem label="用户名" name="username" rules={[{ required: true }]}><Input /></FormItem><FormItem label="密码" name="password" rules={[{ required: true }]}><Input.Password /></FormItem><Button type="primary" htmlType="submit">提交</Button></Form>);
};

4. 总结

模块功能
Form表单容器,管理整体状态
FormItem表单项,管理单个字段的状态和验证
useForm创建和管理表单实例
FormStore表单数据存储
useField管理字段的状态和验证
FormContext提供全局表单配置

如果你希望进一步了解某个具体模块(如 useField 或 FormStore 的实现细节),可以继续深入查看 Ant Design 的源码仓库或官方文档。

相关文章:

  • 免费视频字幕提取工具推荐
  • docker-自动启动java 包
  • [25-cv-06422]David律所代理Dreams USA玩具手办商标维权
  • JavaScript 中 apply、call 和 bind 方法的手写实现
  • Null-text Inversion for Editing Real Images using Guided Diffusion Models
  • JSON 编辑器:从语法编写到结构可视化(一)
  • Element UI 表格el-table宽度不能自适应的问题解决方法
  • 【CF】Day82——Codeforces Round 869 (Div. 2) CD (前缀和 | ⭐无向图找环)
  • zabbix升级文档
  • “储能+热泵+AI”三维驱动,美的能源定义能源科技新未来
  • d3.js研发两组比较的分面柱状图
  • kali系统 windows Linux靶机入侵演练
  • QT5 隐藏控制台窗口方法2025.6.12
  • Java项目中订单未支付过期如何实现自动关单
  • Spring涉及的设计模式以及实际使用场景(含代码)
  • #pragma pack的作用
  • F5深化与Red Hat战略合作 ,赋能企业AI规模化安全部署
  • Lua 的闭包(closure)特性
  • python爬虫ip封禁应对办法
  • 【大模型】实践之1:macOS一键部署本地大模型
  • 档案网站建设的步骤/网站开发工具
  • 网站如何做收款二维码/信息发布平台推广
  • 东南亚做棋牌网站/百度网站的网址
  • 小学学校网站建设计划书/百度投诉平台在哪里投诉
  • 自己设计室内装修软件/如何优化标题关键词
  • 江西中恒建设集团有限公司网站/seo推广公司排名