手把手教你实现一个常用的 antd form 组件

1、Form组件解决的问题
我们从官网摘下来一段Form代码,可以很清晰的看出一个简单的表单,主要是为了统一收集和校验组件的值。 {
console.log(‘values’, values)
}}
>


Submit

那么它是如何做到统一收集和校验呢?原理很简单,只需要通过监听表单组件的onChange事件,获取表单项的 value,根据定义的校验规则对 value 进行检验,生成检验状态和检验信息,再通过setState驱动视图更新,展示组件的值以及校验信息即可。

2、Antd Form 是怎么实现的
要实现上面的方案需要解决这几个问题:

如何实时收集组件的数据?
如何对组件的数据进行校验?
如何更新组件的数据?
如何跨层级传递传递
表单提交
接下来我们就带着这几个问题,一起来一步步实现

3、目录结构

src/index.tsx用于放测试代码
src/components/Form文件夹用于存放Form组件信息
interface.ts用于存放数据类型
useForm存放数据仓库内容
index.tsx导出Form组件相关
FiledContext存放Form全局context
Form外层组件
Filed内层组件
4、数据类型定义
本项目采用ts来搭建,所以我们先定义数据类型;

// src/components/Form/interface.ts
export type StoreValue = any;
export type Store = Record;
export type NamePath = string | number;
export interface Callbacks {
onFinish?: (values: Values) => void;
}
export interface FormInstance {
getFieldValue: (name: NamePath) => StoreValue;
submit: () => void;
getFieldsValue: () => Values;
setFieldsValue: (newStore: Store) => void;
setCallbacks: (callbacks: Callbacks) => void;
}
5、数据仓库
因为我们的表单一定是各种各样不同的数据项,比如input、checkbox、radio等等,如果这些组件每一个都要自己管理自己的值,那组件的数据管理太杂乱了,我们做这个也就没什么必要性了。那要如何统一管理呢?其实就是我们自己定义一个数据仓库,在最顶层将定义的仓库操作和数据提供给下层。这样我们就可以在每层都可以操作数据仓库了。数据仓库的定义,说白了就是一些读和取的操作,将所有的操作都定义在一个文件,代码如下:

// src/components/Form/useForm.ts
import { useRef } from “react”;
import type { Store, NamePath, Callbacks, FormInstance } from “./interface”;
class FormStore {
private store: Store = {};
private callbacks: Callbacks = {};
getFieldsValue = () => {
return { …this.store };
};
getFieldValue = (name: NamePath) => {
return this.store[name];
};
setFieldsValue = (newStore: Store) => {
this.store = {
…this.store,
…newStore,
};
};
setCallbacks = (callbacks: Callbacks) => {
this.callbacks = { …this.callbacks, …callbacks };
};
submit = () => {
const { onFinish } = this.callbacks;
if (onFinish) {
onFinish(this.getFieldsValue());
}
};
getForm = (): FormInstance => {
return {
getFieldsValue: this.getFieldsValue,
getFieldValue: this.getFieldValue,
setFieldsValue: this.setFieldsValue,
submit: this.submit,
setCallbacks: this.setCallbacks,
};
};
}

0 Comments
Leave a Reply