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

手写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 的源码仓库或官方文档。

http://www.xdnf.cn/news/13818.html

相关文章:

  • WPF调用Python心率监测脚本解决方案
  • 【iSAQB软件架构】以架构为中心的开发方法
  • 53. 最大的子数组和
  • iteration和每一轮,训练周期,迭代计数器 这些名词是什么关系?
  • 2025年中国人工智能发展研究报告:技术突破、行业变革与全球竞争新格局
  • ‘Target closed‘ error in Puppeteer解决
  • python打卡day52
  • 【GitOps】Kubernetes安装ArgoCD,使用阿里云MSE云原生网关暴露服务
  • 大数据学习(138)-Hive数据分析3
  • 利用Anything LLM和内网穿透工具在本地搭建可远程访问的AI知识库系统(1)
  • (十二)深度学习计算性能:硬件架构、算法效率与理论极限分析
  • Cursor 编辑器中的 Notepad 功能使用指南
  • sherpa-onnx开源语音处理框架研究报告:从技术解析到应用实践
  • Linux中shell编程的函数递归用法和脚本自动化讲解
  • 什么是JSON ?从核心语法到编辑器
  • 无人机避障——感知篇(在Ubuntu20.04的Orin nx上基于ZED2实现Vins Fusion)
  • 【cobalt strike手册】CS的环境配置
  • 离线部署openstack 2024.1 placement
  • Windows11下搭建Black Magic Probe (BMP) 编译环境
  • 【Unity踩坑】Unity 6在Mac平台编译运行时去除‘trial version‘
  • 第七章——8天Python从入门到精通【itheima】-81~84(函数的多返回值+函数多种传参方式+函数作为参数传递+lambda函数)
  • 剑指offer22_合并两个排序的链表
  • 【C】 USB CDC、Bulk-OUT 端点
  • 观测云,全球领先的监控观测平台亮相亚马逊云科技中国峰会!
  • 迭代优化法解决问题实例
  • day27/60重写(补充)
  • 流体仿真CFD技术在好氧活性污泥曝气系统改造中的应用
  • module_obj笔记
  • 手阳明大肠经之温溜穴
  • MySQL基础知识(DDL、DML)