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

React hook+AntD pro实现Form表单的二次封装

React hook+AntD pro实现Form表单的二次封装

    • 封装Form表单
      • 1、在src/types下新建 antd/form/index.ts,进行Form表的配置、数据等类型的限制
      • 2、在 根目录/components 下新建 BaseForm/index.tsx文件
      • 3、在BaseForm/createFormIpt.tsx中,抽取对不同类型的表单元素渲染
      • 4、在src/pages/PublishArticle/下,新建驱动表单的数据文件data.ts
      • 5、在src/pages/PublishArticle/下,新建使用二次封装的Form组件的父组件index.ts

封装Form表单

关键hooks API: useImperativeHandle、useRef,高阶组件: forwardRef,

1、在src/types下新建 antd/form/index.ts,进行Form表的配置、数据等类型的限制

import React, { ReactNode } from 'react';
import { IButton } from '@/types/antd/button';
// @ts-ignore
import { FilterFunc, GetFieldsValueConfig } from 'rc-field-form/es/interface';type RadioGroupOption = {buttonStyle?: 'outline' | 'solid';name?: string;options?: any[];optionType?: 'default' | 'button',size?: 'large' | 'middle' | 'small',
}type SelectOptions = {mode?: 'multiple' | 'tags';options?: any[];
}
export type FormOptions = {// 表单名称,会作为表单字段 id 前缀使用name: string;labelCol?: number;wrapperCol?: number;autoComplete?: string;// label 是否显示冒号colon?: boolean;// label 标签的文本对齐方式labelAlign?: 'right' | 'left';// 表单布局layout?: 'horizontal' | 'vertical' | 'inline';// 设置字段组件的尺寸(仅限 antd 组件)size?: 'small' | 'middle' | 'large';// initialValues?: {[index: string]: any}
}export type FormItemOptions = {// 是否显示 label 后面的冒号colon?: boolean;// label 标签的文本label?: ReactNode | string;placeholder?: string;name: string;  // use is key// 标签文本对齐方式labelAlign?: 'left' | 'right';labelCol?: number;wrapperCol?: number;noStyle?: boolean;required?: boolean;// 设置防抖,延迟毫秒数后进行校验validateDebounce?: number;// 设置字段校验的时机 : onChangevalidateTrigger?: string | string[];// input 图标prefix?: React.ReactElement;formItemType: string;rules?: {[index: string]: string | boolean}[];formButtons?: IButton[],rows?: number;allowClear?: boolean;selectOptions?: SelectOptions;radioOptions?: RadioGroupOption;
}export interface IFormProps {formOptions: FormOptions;formValue: {[index: string]: any};formItemOptions: FormItemOptions[];emitSubmit?: (formData: any) => void;
}// SystemForm 组件暴露的数据结构
export interface IFormCompExportData {getFieldsValue: (() => any) & ((nameList: (true | any[]), filterFunc?: (FilterFunc | undefined)) => any) & ((config: GetFieldsValueConfig) => any)
}

2、在 根目录/components 下新建 BaseForm/index.tsx文件

子组件:Form的二次封装组件

import React, { forwardRef, useImperativeHandle } from 'react';
import { IFormCompExportData, IFormProps } from '@/types/antd/form';
import createFormIpt from './createFormIpt';
import { Form } from 'antd';const SystemForm = (props: IFormProps, ref: React.Ref<any>) => {const {formOptions,formItemOptions,emitSubmit,formValue,} = props;const [form] = Form.useForm();// useImperativeHandle: 细化ref暴露的实例粒度useImperativeHandle(ref, (): IFormCompExportData=>({// 这里可以暴露SystemForm组件的所有内容  变量、方法、元素实例// 避免暴露出 完整的Form表单实例form  这里选择暴露获取字段value方法getFieldsValue的引用getFieldsValue: form.getFieldsValue}), [])const onFinish = (values: any) => {emitSubmit && emitSubmit(values);};return (<Formform={form}name={formOptions.name}labelCol={{ span: formOptions.labelCol }}wrapperCol={{ span: formOptions.wrapperCol }}initialValues={formValue}autoComplete={formOptions.autoComplete}size={formOptions.size}onFinish={onFinish}>{formItemOptions.map(item => {return (<Form.Itemkey={item.name}label={item.label}name={item.name}rules={item.rules}>{/*<CreateFormIpt formItem={item} />*/}{createFormIpt(item)}</Form.Item>);})}</Form>);
};// 因为有forwardRef包裹,所以SystemForm组件才可以使用第二个参数ref
export default forwardRef(SystemForm);

3、在BaseForm/createFormIpt.tsx中,抽取对不同类型的表单元素渲染

import { FormItemOptions } from '@/types/antd/form';
import React from 'react';
import { Button, Input, Select, Radio } from 'antd';const { TextArea} = Input;const createFormIpt  = (formItem: FormItemOptions) => {if(formItem.name === 'password') {return (<Input type="password" prefix={formItem.prefix} placeholder={formItem.placeholder}/>)}const iptRenderMapByFormItemType: {[index: string]: React.JSX.Element} = {'input': <Input prefix={formItem.prefix} placeholder={formItem.placeholder} allowClear={formItem.allowClear}/>,'textarea':<TextArea  rows={formItem.rows}  placeholder={formItem.placeholder} allowClear={formItem.allowClear} />,'radio': <Radio.Group options={formItem.radioOptions?.options}/>,'select': <Selectplaceholder={formItem.placeholder}mode={formItem.selectOptions?.mode}allowClear={formItem.allowClear}options={formItem.selectOptions?.options}/>,'button': <>{formItem.formButtons?.map(itemBtn=>(<Buttonkey={itemBtn.key}type={itemBtn.buttonType}loading={itemBtn.btnLoadingStatus}block={itemBtn.block}htmlType={itemBtn.htmlType}>{itemBtn.btnDesc}</Button>))}</>,}return iptRenderMapByFormItemType[formItem.formItemType]
}export default createFormIpt;

4、在src/pages/PublishArticle/下,新建驱动表单的数据文件data.ts

import { FormOptions, FormItemOptions } from '@/types/antd/form';export const publishArticleFormValue = {'title': '11s','content': '','summary': '','categoryId': '','tags': [],'isComment': '0','isTop': '0','thumbnail': '',
}// 文章表单
export const publishArticleFormOptions: FormOptions = {name: 'publishArticle',autoComplete: 'off',size: 'large',labelCol: 4,wrapperCol: 20,
}export const publishArticleFormData: FormItemOptions[] = [{label: '文章标题',name: 'title',placeholder: '请输入文章标题',formItemType: 'input',allowClear: true,},{label: '文章摘要',name: 'summary',placeholder: '请输入文章摘要',formItemType: 'textarea',allowClear: true,},{label: '分类',name: 'categoryId',placeholder: '请选择',formItemType: 'select',selectOptions: {},allowClear: true,},{label: '标签',name: 'tags',placeholder: '请选择',formItemType: 'select',selectOptions: {mode: 'multiple'},allowClear: true,},{label: '允许评论',name: 'isComment',formItemType: 'radio',radioOptions: {options: [{ label: '正常', value: '1' },{ label: '停用', value: '0' }]}},{label: '是否置顶',name: 'isTop',formItemType: 'radio',radioOptions: {options: [{ label: '是', value: '1' },{ label: '否', value: '0' }]}},
]

5、在src/pages/PublishArticle/下,新建使用二次封装的Form组件的父组件index.ts

import React, { useRef, useState } from 'react';
import { PageContainer } from '@ant-design/pro-components';
import {publishArticleFormData,publishArticleFormOptions,publishArticleFormValue,
} from '@/pages/PublishArticle/data';
import { IFormCompExportData } from '@/types/antd/form';const PublishArticle: React.FC = () => {// useRef()  其 .current 属性被初始化为传入的参数(initialValue)// 所以useRef的初始化数据类型和useImperativeHandle返回的handle对象数据类型是一致的const publishArticleFormRef = useRef<IFormCompExportData>(null);const test = () => {const { getFieldsValue } = publishArticleFormRef.current as IFormCompExportData;// 获取表单的所有值getFieldsValue(true)console.log('表单收集的值', getFieldsValue(true));}return (<PageContainer><BaseFormformOptions={publishArticleFormOptions}formItemOptions={publishArticleFormData}formValue={publishArticleFormValue}ref={publishArticleFormRef}/><Button type="primary" onClick={test}>获取表单动态值</Button></PageContainer>);
};export default PublishArticle;

相关文章:

React hook+AntD pro实现Form表单的二次封装

React hookAntD pro实现Form表单的二次封装 封装Form表单1、在src/types下新建 antd/form/index.ts&#xff0c;进行Form表的配置、数据等类型的限制2、在 根目录/components 下新建 BaseForm/index.tsx文件3、在BaseForm/createFormIpt.tsx中&#xff0c;抽取对不同类型的表单…...

python异步切片下载文件(内置redis获取任务 mongo更新任务状态等)

异步切片下载二进制文件并上传桶删除本地文件 import json import os import asyncio from urllib import parseimport aiohttp import aioredis from motor.motor_asyncio import AsyncIOMotorClient from retrying import retry from minio import Minio from minio.error im…...

《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(10)-Fiddler如何设置捕获Firefox浏览器的Https会话

1.简介 经过上一篇对Fiddler的配置后&#xff0c;绝大多数的Https的会话&#xff0c;我们可以成功捕获抓取到&#xff0c;但是有些版本的Firefox浏览器仍然是捕获不到其的Https会话&#xff0c;需要我们更进一步的配置才能捕获到会话进行抓包。 2.宏哥环境 1.宏哥的环境是Wi…...

阿里云云原生弹性方案:用弹性解决集群资源利用率难题

作者&#xff1a;赫曦 随着上云的认知更加普遍&#xff0c;我们发现除了以往占大部分的互联网类型的客户&#xff0c;一些传统的企业&#xff0c;一些制造类的和工业型企业客户也都开始使用云原生的方式去做 IT 架构的转型&#xff0c;提高集群资源使用率也成为企业上云的一致…...

Spring-BeanPostProcessor PostConstruct init InitializingBean 执行顺序

执行顺序探究 新建一个对象用于测试 Component public class Student implements InitializingBean {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name name;}public int getAge() {return age;}pu…...

【算法】递归

递归 递归初始递归&#xff1a;数列求和递归的应用&#xff1a;任意进制转换递归深度限制递归可视化&#xff1a;分形树递归可视化&#xff1a;谢尔宾斯基Sierpinski三角形递归的应用&#xff1a;汉诺塔递归的应用&#xff1a;探索迷宫 分治策略和递归优化问题兑换最少个数硬币…...

DC-1靶机刷题记录

靶机下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1GX7qOamdNx01622EYUBSow?pwd9nyo 提取码&#xff1a;9nyo 参考答案&#xff1a; https://c3ting.com/archives/kai-qi-vulnhnbshua-tiDC-1.pdf【【基础向】超详解vulnhub靶场DC-1】 https://www.bilibi…...

rust跟我学七:获取外网IP地址

图为RUST吉祥物 大家好,我是get_local_info作者带剑书生,这里用一篇文章讲解get_local_info是怎么获取到本机的外网IP地址。 首先,先要了解get_local_info是什么? get_local_info是一个获取linux系统信息的rust三方库,并提供一些常用功能,目前版本0.2.4。详细介绍地址:[…...

华为:交换机忘记console密码重置

一、背景 许多旧项目经过长时间使用后&#xff0c;因为没有特定的管理运维人员&#xff0c;初始对接人也将初始账号密码等重要信息丢失&#xff0c;现需要进后台查看配置或更改网络配置&#xff0c;需重置密码 二、重置密码&#xff0c;不重置设备方法 1、使用console插入交…...

2024年甘肃省职业院校技能大赛信息安全管理与评估 样题三 模块一

竞赛需要完成三个阶段的任务&#xff0c;分别完成三个模块&#xff0c;总分共计 1000分。三个模块内容和分值分别是&#xff1a; 1.第一阶段&#xff1a;模块一 网络平台搭建与设备安全防护&#xff08;180 分钟&#xff0c;300 分&#xff09;。 2.第二阶段&#xff1a;模块二…...

Go 中 slice 的 In 功能实现探索

文章目录 遍历二分查找map key性能总结 之前在知乎看到一个问题&#xff1a;为什么 Golang 没有像 Python 中 in 一样的功能&#xff1f;于是&#xff0c;搜了下这个问题&#xff0c;发现还是有不少人有这样的疑问。 补充&#xff1a;本文写于 2019 年。GO 现在已经支持泛型&am…...

pyDAL一个python的ORM(终) pyDAL的一些性能优化

一、大批量插入数据 对于 大量数据插入时&#xff0c;虽然pyDAL也手册中有个方法&#xff1a;bulk_insert()&#xff0c;但是手册也说了&#xff0c;虽然方法上是一次可以多条数据&#xff0c;如果后端数据库是关系型数据库&#xff0c;他转换为SQL时它是一条一条的插入的&…...

springboot log4j配置xml实例说明

提供样本配置代码 xml <?xml version"1.0" encoding"UTF-8"?> <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> <!-- status log4j2内部日志级别 --> <configurat…...

VsCode重新安装需要配机的ESLint和 Prettier - Code formatter 配置

新电脑安装完Vscode后&#xff0c;需要装几个插件&#xff0c;这里记录下&#xff1a; {"diffEditor.ignoreTrimWhitespace": false,"files.autoSave": "afterDelay","editor.codeActionsOnSave": {"source.fixAll.eslint"…...

录屏功能怎么打开?简单操作,一学就会!

录屏功能在当今互联网时代变得越来越重要&#xff0c;无论是游戏录制、在线课程录制还是屏幕操作演示&#xff0c;录屏功能都为我们提供了便捷的解决方案。可是您知道录屏功能怎么打开吗&#xff1f;接下来&#xff0c;让我们一起探索如何在电脑上开启录屏功能&#xff0c;记录…...

小程序显示兼容处理,home键处理

定义&#xff1a; env(safe-area-inset-bottom)和env(safe-area-inset-top)是CSS中的变量&#xff0c;用于获取设备底部和顶部安全区域的大小 示例&#xff1a; padding-bottom: calc(env(safe-area-inset-bottom) 12px); /* 兼容iOS> 11.2 */安全间距类型&#xff1a; …...

【java八股文】之JVM基础篇

【java八股文】之JVM基础篇-CSDN博客 【java八股文】之MYSQL基础篇-CSDN博客 【java八股文】之Redis基础篇-CSDN博客 【java八股文】之Spring系列篇-CSDN博客 【java八股文】之分布式系列篇-CSDN博客 【java八股文】之多线程篇-CSDN博客 【java八股文】之JVM基础篇-CSDN博…...

2024美赛数学建模思路 - 案例:异常检测

文章目录 赛题思路一、简介 -- 关于异常检测异常检测监督学习 二、异常检测算法2. 箱线图分析3. 基于距离/密度4. 基于划分思想 建模资料 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 一、简介 – 关于异常…...

【EI会议征稿通知】2024年通信技术与软件工程国际学术会议 (CTSE 2024)

2024年通信技术与软件工程国际学术会议 (CTSE 2024) 2024 International Conference on Communication Technology and Software Engineering (CTSE 2024) 2024年通信技术与软件工程国际学术会议 (CTSE 2024)将于2024年03月15-17日在中国长沙举行。会议专注于通信技术与软件工…...

Js面试之作用域与闭包

Js面试之作用域与闭包 作用域词法作用域动态作用域 闭包闭包使用场景封装私有变量模块化开发保持变量状态异步操作 注意事项 最近在整理一些前端面试中经常被问到的问题&#xff0c;分为vue相关、react相关、js相关、react相关等等专题&#xff0c;可持续关注后续内容&#xff…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

MFC 抛体运动模拟:常见问题解决与界面美化

在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...

深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏

一、引言 在深度学习中&#xff0c;我们训练出的神经网络往往非常庞大&#xff08;比如像 ResNet、YOLOv8、Vision Transformer&#xff09;&#xff0c;虽然精度很高&#xff0c;但“太重”了&#xff0c;运行起来很慢&#xff0c;占用内存大&#xff0c;不适合部署到手机、摄…...

Unity中的transform.up

2025年6月8日&#xff0c;周日下午 在Unity中&#xff0c;transform.up是Transform组件的一个属性&#xff0c;表示游戏对象在世界空间中的“上”方向&#xff08;Y轴正方向&#xff09;&#xff0c;且会随对象旋转动态变化。以下是关键点解析&#xff1a; 基本定义 transfor…...

​​企业大模型服务合规指南:深度解析备案与登记制度​​

伴随AI技术的爆炸式发展&#xff0c;尤其是大模型&#xff08;LLM&#xff09;在各行各业的深度应用和整合&#xff0c;企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者&#xff0c;还是积极拥抱AI转型的传统企业&#xff0c;在面向公众…...