HOW - 基于组件库组件改造成自定义组件基本规范
文章目录
- Select 选择器改造
- 1. 明确组件目标
- 2. 定义组件 API
- 3. 合理使用默认值
- 4. 支持类型安全的 options 传递
- 5. 支持 ForwardRef(可选)
- 6. 封装样式(可选)
- 7. 使用示例
- ...props 位置
- 推荐顺序:最后
- 原因:
- 简要总结
- 合并内外部逻辑
- 场景示例:处理 onChange
- 方案一:手动合并函数或属性
- 方案二:兼顾默认值 + 用户自定义
- 总结:封装时处理逻辑建议
- 最佳实践示例组件
- 更安全的方式
Select 选择器改造
比如,要将 Ant Design 的 Select
组件封装成你的 CustomSelect
组件并规范化封装,建议遵循以下几个方面的最佳实践:
1. 明确组件目标
你可以定义这个 CustomSelect
的目标,例如:
- 更统一的样式
- 集成默认功能(比如加载状态、本地搜索等)
- 简化使用(比如默认占位符、默认事件处理)
2. 定义组件 API
设计你自己的 CustomSelect
组件的 props 类型时,建议基于 antd 的 SelectProps
做扩展:
// CustomSelect.tsx
import React from 'react';
import { Select, SelectProps } from 'antd';export interface CustomSelectProps extends SelectProps {label?: string; // 可选,封装 labelwrapperClassName?: string; // 可选,外层 class
}const CustomSelect: React.FC<CustomSelectProps> = ({label,wrapperClassName,...props
}) => {return (<div className={wrapperClassName}>{label && <label className="block mb-1 text-gray-700">{label}</label>}<Select {...props} /></div>);
};export default CustomSelect;
3. 合理使用默认值
在封装中添加默认值可以提升使用体验:
<SelectshowSearchallowClearplaceholder="请选择"optionFilterProp="label"filterOption={(input, option) =>(option?.label ?? '').toLowerCase().includes(input.toLowerCase())}{...props}
/>
你可以在 CustomSelect
内设置 showSearch
、allowClear
、filterOption
等默认行为。
4. 支持类型安全的 options 传递
你可以加一个 options
支持(类型为 DefaultOptionType[]
):
import type { DefaultOptionType } from 'antd/es/select';interface CustomSelectProps extends SelectProps {options?: DefaultOptionType[];
}
并配合传入:
<Selectoptions={props.options}{...otherProps}
/>
5. 支持 ForwardRef(可选)
如果你希望外部能访问内部 ref
,可以使用 forwardRef
:
const CustomSelect = React.forwardRef<any, CustomSelectProps>((props, ref) => {return <Select ref={ref} {...props} />;
});
6. 封装样式(可选)
统一样式可以放在 CustomSelect.module.css
或用 tailwind
写死样式:
<Select className="w-full rounded-md" />
7. 使用示例
<CustomSelectlabel="城市"value={selectedCity}onChange={setSelectedCity}options={[{ label: '北京', value: 'beijing' },{ label: '上海', value: 'shanghai' }]}
/>
…props 位置
{...props}
应该放在 最后面。
推荐顺序:最后
<SelectshowSearchallowClearplaceholder="请选择"{...props}
/>
原因:
-
避免被覆盖
如果你把...props
放在前面,后面设置的属性会覆盖它,导致用户传入的属性失效。// 错误示例(可能导致用户传入的属性无效) <Select{...props}showSearch={false} // 会覆盖 props.showSearch,即使用户传了 true />
-
正确示例:用户可以覆盖默认行为
<SelectshowSearchallowClearplaceholder="请选择"{...props} // 用户传入的值会覆盖上面的默认值 />
例如用户传入
allowClear={false}
,最终就会生效。
简要总结
放置位置 | 是否推荐 | 原因说明 |
---|---|---|
最后面 | ✅ 推荐 | 用户传入值可覆盖默认值 |
最前面 | ❌ 不推荐 | 默认值会覆盖用户传入值,造成困惑 |
如果你还封装了内部逻辑(比如 onChange
的包裹处理),那可以手动合并它,而不是直接写在默认值中。
合并内外部逻辑
如果你希望在自定义组件中:
内部自定义属性可以“加工”后使用
同时仍 兼容外部传进来的属性,即可以被用户覆写/增强
场景示例:处理 onChange
我们以 onChange
为例,如果你想在组件内部处理一些逻辑后再执行用户传入的 onChange
,做法如下:
方案一:手动合并函数或属性
const handleChange = (value: any, option: any) => {// 自定义逻辑,比如打日志console.log('[CustomSelect] selected:', value);// 调用外部传入的 onChange(如果有)props.onChange?.(value, option);
};<SelectshowSearchallowClearplaceholder="请选择"{...props}onnChange={handleChange}
/>
方案二:兼顾默认值 + 用户自定义
例如:
<SelectshowSearch={props.showSearch ?? true} // 外部可以传 false,否则默认 trueallowClear={props.allowClear ?? true}placeholder={props.placeholder ?? '请选择'}{...props}
/>
这样可以兼顾默认值 + 用户自定义。
总结:封装时处理逻辑建议
类型 | 写法 | 是否允许外部覆盖 |
---|---|---|
函数型属性 | 主动调用外部函数(如 onChange) | ✅ 推荐 |
布尔/字符串属性 | 使用 ?? 提供默认值 | ✅ 推荐 |
最佳实践示例组件
export const CustomSelect: React.FC<CustomSelectProps> = ({label,wrapperClassName,onChange,...props
}) => {const handleChange = (value: any, option: any) => {// 内部逻辑console.log('[CustomSelect] selected:', value);// 外部逻辑onChange?.(value, option);};return (<div className={wrapperClassName}>{label && <label className="block mb-1 text-gray-700">{label}</label>}<SelectshowSearch={props.showSearch ?? true}allowClear={props.allowClear ?? true}placeholder={props.placeholder ?? '请选择'}{...props}onChange={handleChange}/></div>);
};
更安全的方式
更安全的方式是明确列出你需要的 props,而不是使用 {...props}
:
const handleChange = (value: any, option: any) => {// 内部逻辑console.log('[CustomSelect] selected:', value);// 外部逻辑onChange?.(value, option);};<SelectshowSearchallowClearplaceholder="请选择"onChange={handleChange}// 明确列出其他需要的 propsstyle={props.style}className={props.className}// 其他需要的 props...
/>
即建议不要偷懒,直接使用 ...props
,而是使用什么传入什么。并且可以参考 onChagne
一样合并内外部逻辑。
相关文章:
HOW - 基于组件库组件改造成自定义组件基本规范
文章目录 Select 选择器改造1. 明确组件目标2. 定义组件 API3. 合理使用默认值4. 支持类型安全的 options 传递5. 支持 ForwardRef(可选)6. 封装样式(可选)7. 使用示例 ...props 位置推荐顺序:最后原因:简要…...

九州未来十三载:开源赋能 智启未来
2012年,九州未来以“开源赋能云边变革”为使命,开启中国开放云边基础架构服务的探索之路。十三载坚守深耕,我们始终以开源为翼,以算力为基,在科技浪潮中砥砺前行,见证并推动着AI时代的算力变革。 坚守初心丨…...

2025年AI搜索引擎发展洞察:技术革新与市场变革
引言:AI搜索的崛起与市场格局重塑 2024-2025年,AI搜索市场迎来了前所未有的变革期。随着DeepSeek-R1等先进大语言模型的推出,传统搜索引擎、AI原生搜索平台以及各类内容平台纷纷加速智能化转型,推动搜索技术从基础信息检索向深度…...

dify调用Streamable HTTP MCP应用
一、概述 上一篇文章,介绍了使用python开发Streamable HTTP MCP应用,链接:https://www.cnblogs.com/xiao987334176/p/18872195 接下来介绍dify如何调用MCP 二、插件 安装插件 需要安装2个插件,分别是:Agent 策略(支持 …...

HCIP实验五
一、实验拓扑图: 二、实验需求分析: 1. PreVal策略:要求确保R4通过R2到达192.168.10.0/24 ,需在R4上针对去往该网段路由配置PreVal策略,为经R2的路径赋予更高优先值,影响本地路由表选路。 2. AS Path策略…...
java将图片转Base64字符串存储mysql数据库
1、mysql数据库的表里新增一个字段image_data,使用TEXT或LONGTEXT类型: CREATE TABLE IMAGES( id INT AUTO_INCREMENT PRIMARY KEY, image_name VARCHAR(255), image_data LONGTEXT, upload_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); 2、Java核心…...
题目 3330: 蓝桥杯2025年第十六届省赛真题-01 串
题目 3330: 蓝桥杯2025年第十六届省赛真题-01 串 时间限制: 2s 内存限制: 192MB 提交: 310 解决: 24 题目描述 给定一个由 0, 1, 2, 3 的二进制表示拼接而成的长度无限的 01 串。 其前若干位形如 011011100101110111 。 请求出这个串的前 x 位里有多少个 1 。 输入格…...
初识 Flask 框架
目录 1. Flask 框架概述 1.1 安装 Flask 1.2 创建你的第一个 Flask 应用 1.3 运行 Flask 应用 2. Flask 路由与视图函数 2.1 动态路由 2.2 支持多种 HTTP 请求方法 2.3 使用 Jinja2 模版渲染 HTML 2.5 模版继承与块 3. Flask 表单处理与用户输入 3.1 安装 Flask-WTF …...
MYSQL故障排查和环境优化
一、MySQL故障排查 1. 单实例常见故障 (1)连接失败类问题 ERROR 2002 (HY000): Cant connect to MySQL server 原因:MySQL未启动或端口被防火墙拦截。 解决:启动MySQL服务(systemctl start mysqld)或开放…...

vivado fpga程序固化
一般下载到fpga上的程序在掉电之后就会丢失,如果想要掉电之后程序不丢失,就需要将比特流文件固化到板载的flash上。 以下以我的7a100t开发板为例,介绍程序固化的流程 点击OK就可以下载了。 一个奇怪的问题 有一次我的一个工程固化之后&…...

OpenCV CUDA模块图像特征检测与描述------图像中快速检测特征点类cv::cuda::FastFeatureDetector
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::cuda::FastFeatureDetector 是 OpenCV 的 CUDA 加速模块中的一部分,用于在图像中快速检测特征点。FAST(Features fro…...

SpringMVC(结合源码浅析工作流程)
SpringMVC 概念 Spring MVC 是基于前端控制器(Front Controller)设计模式的 Web 框架,在 Web 应用中指一个统一的入口,用来接收所有客户端请求,并统一进行分发、处理。在 SpringMVC 中,前端控制器就是 Di…...

学习STC51单片机13(芯片为STC89C52RC)
我去,兄弟们我们今天来学习一个牛逼 的硬件,它叫超声波测距模块HC—SR04 硬件:HC—SR04 哎,想当初最想要玩的就是这个模块,科技感十足,那现在就让我们玩玩吧 超声波测距传感器 原理就是说需要给Trig 10u…...

Claude 4 系列 Opus 4 与 Sonnet 4正式发布:Claude 4新特性都有哪些?
随着 Claude 4 系列(Opus 4 与 Sonnet 4)的正式发布,Anthropic 把自家大模型从“会聊天”推进到“能当自主代理”──不仅推理更深、上下文更长,还内置代码执行、多模态理解、工具调用等一揽子全新能力;同时࿰…...
Swagger API 未授权访问漏洞【原理扫描】修复
一、背景 漏洞名称:Swagger API 未授权访问漏洞【原理扫描】 风险等级:中 详细描述: Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务,方便开发者快速了解和调试接口。但由于…...

深度“求索”:DeepSeek+Dify构建个人知识库
目录 前言 环境部署 安装Docker 安装Dify 配置Dify 部署知识库 创建应用 前言 在当今数字化信息爆炸的时代,数据隐私和个性化知识管理成为企业和个人关注的焦点。Dify,作为一款备受瞩目的开源 AI 应用开发平台,为用户提供了完整的私有…...

基于R语言的空间异质性数据分析技术
在自然和社会科学领域,存在大量与地理或空间相关的数据,这些数据通常具有显著的空间异质性。传统的统计学方法在处理这类数据时往往力不从心。基于R语言的一系列空间异质性数据分析方法,如地理加权回归(GWR)、地理加权…...
C++:动态刷新打印内容
目录 1.简介1.1 Display类原理简述 2.代码2.1 main.cpp:无注释版2.2 main.cpp:有注释版 3.编译运行 1.简介 本文介绍一个用于命令行动态覆盖输出的C实现(Display类); 效果说明: 普通输出会直接换行显示。…...

网络学习-TCP协议(七)
一、TCP协议 TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。 1、三次握手 客户端: 1、先发起连接,发送SYN置1,seqnum12345(随机值)----半连接…...

基于微信小程序的高校校园微活动管理系统设计与实现(源码+定制+开发)高校微信小程序校园活动发布与互动平台开发 面向大学生群体的校园活动移动平台设计与实现
博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…...
Python 项目中安装 OpenAI 库的详细指南
在 Windows 系统中指定版本安装 OpenAI 库的指南 在 Windows 系统中,尤其是使用 Python 3.7.8 时,安装 OpenAI 库可能会遇到一些问题。本文将为你提供一个简单易懂的解决方案,帮助你成功安装指定版本的 OpenAI 库。 一、问题背景 当你在 W…...

云计算与大数据进阶 | 27、存储系统如何突破容量天花板?可扩展架构的核心技术与实践—— 分布式、弹性扩展、高可用的底层逻辑(上)
数据中心里,存储系统是至关重要的组成部分。由于相关硬件组件与存储操作系统的多样性和复杂性,如何在保证存储稳定、安全、可靠的同时,实现灵活扩展和自服务,一直是困扰数据中心全面云化的难题。 简单来说,现在的难题…...
使用Gemini, LangChain, Gradio打造一个书籍推荐系统 (第二部分)
建立向量嵌入数据库 from langchain_community.document_loaders import TextLoader from langchain_text_splitters import CharacterTextSplitter from langchain.docstore.document import Document from langchain_chroma.vectorstores import Chromaimport vertexai from…...

IvorySQL-WASM:免安装的数据库探索之旅
简介 为了降低社区用户的使用门槛,提升使用体验,IvorySQL 社区特别推出了 IvorySQL-WASM 项目,帮助用户快速在线 Demo。 IvorySQL-WASM 基于开源的 Postgres-WASM 框架开发。它允许用户直接在网页浏览器中体验 IvorySQL,无需本地…...

飞牛fnNAS远程映射盘符
目录 一、NAS、PC端配置Zerotier 二、使用网上邻居 三、使用WebDAV 1.开启WebDAV 2.PC上安装RaiDrive并设置 如果能将NAS作为本机一个盘符来使用,一定会令我非常方便。如果是本地,可以很方便实现。 将飞牛NAS映射为本地盘符,常用两种方式,一种是网上邻居,另一种是We…...

Java设计模式:探索编程背后的哲学
设计模式是软件开发中的一种常见方法,它为常见问题提供了解决方案。在Java世界中,设计模式的应用尤为广泛。本文将深入探讨Java设计模式的起源、分类和实际应用,帮助读者更好地理解和应用这些模式。设计模式不仅是编程的技术,更是…...
会话管理有哪些
使用服务器或者框架的会话管理控制。应用程序应当只识别有效的会话标识符。 会话标识符必须总是在一个可信系统(比如:服务器)上创建。 会话管理控制应当使用通过审查的算法以保证足够的随机会话标识符。 为包含已验证的会…...
《C++20新特性全解析:模块、协程与概念(Concepts)》
引言:C20——现代C的里程碑 C20是继C11之后最具革命性的版本,它通过模块(Modules)、协程(Coroutines)和概念(Concepts)三大核心特性,彻底改变了C的代码组织方式、并发模…...

Docker部署OpenSearch集群
OpenSearch 简介 OpenSearch 是一款开源的搜索与分析引擎,最初由亚马逊 AWS 开发,于 2021 年 9 月将其移交至 Linux 基金会旗下的 OpenSearch 软件基金会,此后实现了社区主导的治理模式。其具有高性能、可扩展性强、兼容性强等优点ÿ…...
三宽用到的网络类型
用家宽、企宽和专线运行P2P的网络类型本质要求一致,但具体配置和优化方向因宽带类型而异。以下是关键差异与共性分析: 一、核心网络类型要求(三者的共性) 公网IP 必要性:均需公网IP(非内网IP)以…...