React 如何封裝一個可復用的 Ant Design 組件

文章目錄

  • 前言
    • 一、為什么需要封裝組件?
    • 二、 仿antd組件的Button按鈕
    • 三、封裝一個可復用的表格組件 (實戰)
      • 1. 明確需求
      • 2. 設計組件 API
      • 3. 實現組件代碼
      • 4. 使用組件
    • 三、封裝組件的最佳實踐
    • 四、進階優化
  • 總結


前言

作為一名前端開發工程師,在日常項目中,我們經常會使用 UI 框架(如 Ant Design)來快速搭建界面。然而,直接使用框架組件可能會導致代碼重復、樣式不統一或功能擴展困難。本文將以封裝一個 可復用的表格組件 為例,分享如何基于 Ant Design(antd)封裝自己的業務組件,提升開發效率和代碼質量。


一、為什么需要封裝組件?

  1. 代碼復用:避免重復編寫相同的邏輯和樣式。
  2. 統一風格:確保項目中的組件風格一致。
  3. 功能擴展:在基礎組件上添加業務邏輯(如分頁、搜索、權限控制等)。
  4. 降低維護成本:修改一處即可影響所有使用該組件的地方。

二、 仿antd組件的Button按鈕

雖然有些人要問,antd組件庫有現成的Button為啥不用,還要自己封裝,難道你封裝的比別人好?在此說明,本篇文章只是講解封裝思想,別人怎么封裝的。

  1. 首先新建一個專門存放組件的文件夾—我的就叫做XLButton了
    index.tsx – 存放模板
    index.scss存放樣式

在這里插入圖片描述

  1. 確定模板和樣式
import "./index.scss";interface XLButtonProps {type?: "primary" | "default" | "danger";size?: "small" | "middle" | "large";children?: React.ReactNode;
}const XLButton: React.FC<XLButtonProps> = (props) => {const typeStyle =props.type === "primary"? "xl-button-primary": props.type === "danger"? "xl-button-danger": "xl-button-default";const sizeStyle =props.size === "small"? "xl-button-small": props.size === "middle"? "xl-button-middle": "xl-button-large";return (<button className={`${typeStyle} ${sizeStyle}`}>{props.children || "Default Button"}</button>);
};export default XLButton;
// index.scss
button {color: #fff;width: 123px;height: 36px;border-radius: 6px;outline: none;border: none;margin-right: 20px;
}.xl-button-primary,
.xl-button-danger,
.xl-button-default {padding: 8px 16px;border: none;border-radius: 4px;cursor: pointer;transition: all 0.3s ease;
}// 尺寸樣式
.xl-button-small {width: 60px;height: 30px;padding: 0 8px;font-size: 12px;
}.xl-button-middle {height: 32px;padding: 4px 16px;font-size: 14px;
}.xl-button-large {height: 40px;padding: 8px 24px;font-size: 16px;
}.xl-button-primary {background-color: #1890ff;color: white;
}.xl-button-danger {background-color: #ff4d4f;color: white;
}.xl-button-default {background-color: #fff;border: 1px solid #d9d9d9;color: #333;
}.xl-button-default:hover {border-color: #1890ff !important;color: #1890ff;
}.xl-button-danger:hover,
.xl-button-primary:hover {opacity: 0.8;box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
  1. 使用 -引入組件
import XLButton from "../Components/XLButton";
const Home = () => {return (<div><h1>仿antd按鈕</h1><XLButton type="danger">我是danger</XLButton ><XLButton type="primary">我是primary</XLButton ><XLButton >我是默認</XLButton ></div>);
};export default Home;

在這里插入圖片描述

三、封裝一個可復用的表格組件 (實戰)

有了上面的思想,現在讓我們來封裝一個自己的表格組件。進一步強化

1. 明確需求

假設我們需要封裝一個支持以下功能的表格組件:

  • 分頁(pagination)
  • 搜索(search)
  • 列排序(sortable columns)
  • 自定義列渲染
  • 加載狀態(loading)
  • 空數據提示(empty text)

2. 設計組件 API

首先,設計組件的 props 接口,明確外部傳入的參數:

	import React from 'react';import { Table, Input, Button, Space } from 'antd';import type { TableProps, ColumnsType } from 'antd';interface EnhancedTableProps<RecordType extends object = any> {columns: ColumnsType<RecordType>; // 表格列配置dataSource: RecordType[]; // 表格數據loading?: boolean; // 加載狀態emptyText?: React.ReactNode; // 空數據提示pagination?: TableProps<RecordType>['pagination']; // 分頁配置onSearch?: (value: string) => void; // 搜索回調onSort?: (field: string, order: 'ascend' | 'descend') => void; // 排序回調}

3. 實現組件代碼

以下是完整的組件實現代碼:

import React, { useState } from "react";
import { Table, Input, Space } from "antd";
import type { TableProps } from "antd";
import type { ColumnsType } from "antd/es/table";
import { SearchOutlined } from "@ant-design/icons";interface EnhancedTableProps<RecordType> {columns: ColumnsType<RecordType>;dataSource: RecordType[];loading?: boolean;emptyText?: React.ReactNode;pagination?: TableProps<RecordType>["pagination"];onSearch?: (value: string) => void;onSort?: (field: string, order: "ascend" | "descend") => void;
}const MyTable = <RecordType extends object>({columns,dataSource,loading = false,emptyText = "暫無數據",pagination,onSearch,onSort,
}: EnhancedTableProps<RecordType>) => {const [searchValue, setSearchValue] = useState("");// 處理搜索const handleSearch = () => {if (onSearch) {onSearch(searchValue.trim());}};// 處理排序const handleChange: TableProps<RecordType>["onChange"] = (pagination,filters,sorter) => {if (Array.isArray(sorter)) {// 處理多列排序的情況const firstSorter = sorter[0];if (firstSorter?.field && onSort) {onSort(firstSorter.field as string,firstSorter.order as "ascend" | "descend");}} else if (sorter?.field && onSort) {// 處理單列排序的情況onSort(sorter.field as string, sorter.order as "ascend" | "descend");}};return (<div>{/* 搜索框 */}<Space style={{ marginBottom: 16 }}><Input.Searchplaceholder="請輸入搜索內容"value={searchValue}onChange={(e) => setSearchValue(e.target.value)}onSearch={handleSearch}enterButton={<SearchOutlined />}/></Space>{/* 表格 */}<Table<RecordType>columns={columns}dataSource={dataSource}loading={loading}pagination={pagination}onChange={handleChange}locale={{emptyText,}}/></div>);
};export default MyTable;

4. 使用組件

在其他地方使用封裝好的 EnhancedTable 組件:

import XLBuuton from "../Components/XLButton";
import MyTable from "../Components/MyTable";
import type { ColumnsType } from "antd/es/table";interface User {key: number;name: string;age: number;address: string;
}const columns: ColumnsType<User> = [{title: "姓名",dataIndex: "name",key: "name",sorter: (a: User, b: User) => a.name.localeCompare(b.name),},{title: "年齡",dataIndex: "age",key: "age",sorter: (a: User, b: User) => a.age - b.age,},{title: "地址",dataIndex: "address",key: "address",},
];const dataSource: User[] = [{key: 1,name: "張三",age: 32,address: "北京市朝陽區",},{key: 2,name: "李四",age: 42,address: "上海市浦東新區",},{key: 3,name: "李四",age: 42,address: "上海市浦東新區",},{key: 4,name: "李四",age: 42,address: "上海市浦東新區",},{key: 5,name: "李四",age: 42,address: "上海市浦東新區",},{key: 6,name: "李四",age: 42,address: "上海市浦東新區",},{key: 7,name: "李四",age: 42,address: "上海市浦東新區",},
];const Home = () => {return (<div><h1>仿antd按鈕</h1><XLBuuton type="danger">我是danger</XLBuuton><XLBuuton type="primary">我是primary</XLBuuton><XLBuuton>我是默認</XLBuuton><hr /><h1>自定義表格--包含分頁和搜索排序</h1><MyTable<User>columns={columns}dataSource={dataSource}pagination={{ pageSize: 5 }}onSearch={(value) => console.log("搜索:", value)}onSort={(field, order) => console.log("排序:", field, order)}/></div>);
};export default Home;

在這里插入圖片描述
在這里插入圖片描述

三、封裝組件的最佳實踐

  1. 類型安全

    • 使用 TypeScript 定義組件的 props 和內部狀態。
    • 避免使用 any 類型,確保類型推斷正確。
  2. 可擴展性

    • 通過 props 暴露必要的配置項(如分頁、搜索、排序等)。
    • 支持自定義渲染(如 render 函數)。
  3. 默認值

    • 為可選 props 提供合理的默認值,減少重復代碼。
  4. 樣式隔離

    • 使用 CSS Modules 或 CSS-in-JS 避免樣式污染。
    • 通過 classNamestyle 允許外部覆蓋樣式。
  5. 文檔和示例

    • 編寫清晰的 README,說明組件的用途、API 和使用示例。
    • 提供 Storybook 或類似工具展示組件的交互效果。

四、進階優化

  1. 國際化(i18n)

    • 支持多語言文本(如空數據提示)。
  2. 主題定制

    • 通過 CSS 變量或主題配置文件支持主題切換。
  3. 性能優化

    • 使用 React.memo 避免不必要的重渲染。
    • 對大數據量表格使用虛擬滾動(如 react-window)。
  4. 單元測試

    • 編寫 Jest 或 React Testing Library 測試用例,確保組件行為符合預期。

總結

通過封裝 Ant Design 組件,我們可以:

  1. 提升開發效率,減少重復代碼。
  2. 統一項目風格,降低維護成本。
  3. 快速響應業務需求變化,擴展組件功能。

封裝組件的核心思想是 抽象公共邏輯,暴露靈活配置。希望本文的分享能幫助你在實際項目中更好地復用和擴展 Ant Design 組件!如果你有其他封裝組件的經驗或問題,歡迎在評論區交流!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/84311.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/84311.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/84311.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

STC89C52RC/LE52RC

STC89C52RC 芯片手冊原理圖擴展版原理圖 功能示例LED燈LED燈的常亮效果LED燈的閃爍LED燈的跑馬燈效果&#xff1a;從左到右&#xff0c;從右到左 數碼管靜態數碼管數碼管計數mian.cApp.cApp.hCom.cCom.hDir.cDir.hInt.cInt.hMid.cMid.h 模板mian.cApp.cApp.hCom.cCom.hDir.cDir…

踩坑記錄:RecyclerView 局部刷新notifyItemChanged多次調用只觸發一次 onBindViewHolder 的原因

1. 問題背景 在做項目的時候&#xff0c;RecyclerView需要使用局部刷新&#xff0c;使用 notifyItemChanged(position, payload) 實現局部刷新&#xff0c;但發現調用多次只執行了一次&#xff0c;第二個刷新不生效。 2. 錯誤示例&#xff08;只處理 payloads.get(0)&#xff…

OpenLayers 加載鷹眼控件

注&#xff1a;當前使用的是 ol 5.3.0 版本&#xff0c;天地圖使用的key請到天地圖官網申請&#xff0c;并替換為自己的key 地圖控件是一些用來與地圖進行簡單交互的工具&#xff0c;地圖庫預先封裝好&#xff0c;可以供開發者直接使用。OpenLayers具有大部分常用的控件&#x…

WPF···

設置啟動頁 默認最后一個窗口關閉,程序退出,可以設置 修改窗體的icon圖標 修改項目exe圖標 雙擊項目名會看到代碼 其他 在A窗體點擊按鈕打開B窗體,在B窗體設置WindowStartupLocation=“CenterOwner” 在A窗體的代碼設置 B.Owner = this; B.Show(); B窗體生成在A窗體中間…

github公開項目爬取

import requestsdef search_github_repositories(keyword, tokenNone, languageNone, max_results1000):"""通過 GitHub API 搜索倉庫&#xff0c;支持分頁獲取所有結果&#xff08;最多 1000 條&#xff09;:param keyword: 搜索關鍵詞:param token: GitHub To…

防震基座在半導體晶圓制造設備拋光機詳細應用案例-江蘇泊蘇系統集成有限公司

在半導體制造領域&#xff0c;晶圓拋光作為關鍵工序&#xff0c;對設備穩定性要求近乎苛刻。哪怕極其細微的振動&#xff0c;都可能對晶圓表面質量產生嚴重影響&#xff0c;進而左右芯片制造的成敗。以下為您呈現一個防震基座在半導體晶圓制造設備拋光機上的經典應用案例。 企…

S32K開發環境搭建詳細教程(一、S32K IDE安裝注冊)

一、S32K IDE安裝注冊 1、進入恩智浦官網https://www.nxp.com.cn/&#xff08;需要在官網注冊一個賬號&#xff09; 2、直接搜索 “Standard Software”&#xff0c;找到S32K3 Standard Software&#xff0c;點擊進入 3、下載 (1)Automotive SW - S32K3 - S32 Design Studio…

Spring Cloud Gateway 微服務網關實戰指南

上篇文章簡單介紹了SpringCloud系列OpenFeign的基本用法以及Demo搭建&#xff08;Spring Cloud實戰&#xff1a;OpenFeign遠程調用與服務治理-CSDN博客&#xff09;&#xff0c;今天繼續講解下SpringCloud Gateway實戰指南&#xff01;在分享之前繼續回顧下本次SpringCloud的專…

MSP430G2553 USCI模塊串口通信

1.前言 最近需要利用msp430連接藍牙模塊傳遞數據&#xff0c;于是死磕了一段時間串口&#xff0c;在這里記錄一下 2.msp430串口模塊 msp430的串口模塊可以有USCI模塊提供 在異步模式中&#xff0c; USCI_Ax 模塊通過兩個外部引腳&#xff0c; UCAxRXD 和 UCAxTXD&#xff0…

【產品經理從0到1】用戶端產品設計與用戶畫像

思考 xx新聞的第一個版本應該做哪些事情呢&#xff1f; 用戶端核心功能 用戶端通用頁面設計 思考 回想一下&#xff0c;大家在第一次使用一個新下載的App的時候會看到一些什么樣的頁面?這樣的頁面一般都是展示了一些什么內容? 引導頁 概念 第一次安裝App或者更新App后第…

多場景游戲AI新突破!Divide-Fuse-Conquer如何激發大模型“頓悟時刻“?

多場景游戲AI新突破&#xff01;Divide-Fuse-Conquer如何激發大模型"頓悟時刻"&#xff1f; 大語言模型在強化學習中偶現的"頓悟時刻"引人關注&#xff0c;但多場景游戲中訓練不穩定、泛化能力差等問題亟待解決。Divide-Fuse-Conquer方法&#xff0c;通過…

佰力博科技與您探討壓電材料的原理與壓電效應的應用

壓電材料的原理基于正壓電效應和逆壓電效應&#xff0c;即機械能與電能之間的雙向轉換特性。 壓電材料的原理源于其獨特的晶體結構和電-機械耦合效應&#xff0c;具體可分為以下核心要點&#xff1a; 1. ?正壓電效應與逆壓電效應的定義? ?正壓電效應?&#xff1a;當壓電…

算法備案審核周期

&#xff08;一&#xff09;主體備案審核 主體備案審核周期通常為7-10個工作日&#xff0c;監管部門將對企業提交的資質信息進行嚴格審查&#xff0c;審核重點包括&#xff1a; 營業執照的真實性、有效性及與備案主體的一致性。法人及算法安全責任人身份信息的準確性與有效性…

管理系統的接口文檔

一、接口概述 本接口文檔用于描述圖書管理系統中的一系列 Restful 接口&#xff0c;涵蓋圖書的查詢、添加、更新與刪除操作&#xff0c;以及用戶的登錄注冊等功能&#xff0c;方便客戶端與服務器之間進行數據交互。 二、接口基礎信息 接口地址&#xff1a;https://book-manag…

杰發科技AC7801——PWM獲取固定脈沖個數

測試通道6 在初始化時候打開通道中斷 void PWM1_GenerateFrequency(void) {PWM_CombineChConfig combineChConfig[1]; //組合模式相關結構體PWM_IndependentChConfig independentChConfig[2];//獨立模式相關結構體PWM_ModulationConfigType pwmConfig; //PWM模式相關結構體PWM…

RL電路的響應

學完RC電路的響應&#xff0c;又過了一段時間了&#xff0c;想必很多人都忘了RC電路響應的一些內容。我們這次學習RL電路的響應&#xff0c;以此同時&#xff0c;其實也是帶大家一起回憶一些之前所學的RC電路的響應的一些知識點。所以&#xff0c;這次的學習&#xff0c;其實也…

鴻蒙Flutter實戰:21-混合開發詳解-1-概述

引言 在前面的系列文章中&#xff0c;我們從搭建開發環境開始&#xff0c;講到如何使用、集成第三方插件&#xff0c;如何將現有項目進行鴻蒙化改造&#xff0c;以及上架審核等內容&#xff1b;還以高德地圖的 HarmonyOS SDK 的使用為例&#xff0c; 講解了如何將高德地圖集成…

Vmware ubuntu22.04 虛擬機 連接Windows主機虛擬串口

1. Windows虛擬串口配置 虛擬串口下載&#xff1a;教程網址 虛擬串口使用&#xff1a;教程網址 2. Ubuntu 虛擬串口配置 Vmware ubuntu22.04 虛擬機 連接windows主機虛擬串口_vmware中ttys0連接的是哪個端口-CSDN博客 注意&#xff1a;虛擬添加串口的時候&#xff0c;一直…

編譯rk3568的buildroot不起作用

一、環境&#xff1a; 使用kickpi k1開發板&#xff0c;芯片為rk3568。 vmware ubuntu22.04 kickpi給的sdk包&#xff0c;應該不同友商是通用的。 使用的根文件為buildroot 二、問題&#xff1a; 由于 1、wpa_supplicant -D wext -c /etc/wpa_supplicant.conf -i wlan0 …

【動態規劃】簡單多狀態(二)

&#x1f4dd;前言說明&#xff1a; 本專欄主要記錄本人的基礎算法學習以及LeetCode刷題記錄&#xff0c;按專題劃分每題主要記錄&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代碼&#xff1b;&#xff08;2&#xff09;優質解法 優質代碼&#xff1b;&#xff…