React 單一職責原則:優化組件設計與提高可維護性

fileOf7174.png

單一職責原則(SRP)

在 React 中,組件是構建 UI 的核心單位,而良好的組件設計是保證應用質量和可維護性的關鍵。單一職責原則是一種設計原則,也適用于 React 組件的開發。它強調每個組件應該只關注一個職責,這樣可以提高組件的可維護性、復用性以及降低代碼的復雜度。

什么是單一職責原則

單一職責原則的定義是每個類應該只有一個職責, ? 也就是只做一件事。這個原則是最容易解釋的,因為我們可以簡單地將其理解為“每個功能/模塊/組件都應該只做一件事”。

在 React 組件中,單一職責原則要求將組件的功能分解為更小的部分,每個部分只負責一個特定的職責。這樣做的好處是,當需求發生變化時,只需要修改與該職責相關的部分,而不會影響整個組件。這提高了代碼的可維護性和可測試性。

在所有這些原則中,單一職責原則是最容易遵循的,也是最有影響力的一項,因為它極大提高了代碼的質量。為了確保組件只做一件事,可以這樣:

  • 將功能較多的大型組件拆分為較小的組件;

  • 將與組件功能無關的代碼提取到單獨的函數中;

  • 將有聯系的功能提取到自定義 Hooks 中。

如何應用單一職責原則在 React 中

在 React 中應用單一職責原則主要通過組件的拆分和組合來實現。以下是一些建議:

  1. 拆分大型組件:當一個組件變得龐大且復雜時,考慮將其拆分為更小的組件,每個組件關注不同的職責。這樣可以提高可維護性和復用性。

  2. 提取可復用的功能:識別重復使用的功能,將其提取為單獨的組件,并通過 props 進行參數化。這樣可以減少重復代碼,提高復用性。

  3. 保持組件的簡潔和獨立性:確保每個組件只關注自己的職責,并且不包含與其他職責無關的代碼。這樣可以降低代碼的復雜度和維護成本。

  4. 使用高階組件(Higher-Order Components):高階組件是一種函數,接受一個組件作為參數,并返回一個新的增強組件。通過使用高階組件,可以將與特定職責相關的邏輯與組件分離,提高代碼的可維護性。

  5. 使用自定義鉤子(Custom Hooks):自定義鉤子是一種將組件邏輯進行復用的方式。通過將與特定職責相關的邏輯封裝在自定義鉤子中,可以使組件更加簡潔和獨立。

下面來看一個顯示活躍用戶列表的組件:

const?ActiveUsersList?=?()?=>?{const?[users,?setUsers]?=?useState([])useEffect(()?=>?{const?loadUsers?=?async?()?=>?{??const?response?=?await?fetch('/some-api')const?data?=?await?response.json()setUsers(data)}loadUsers()},?[])const?weekAgo?=?new?Date();weekAgo.setDate(weekAgo.getDate()?-?7);return?(<ul>{users.filter(user?=>?!user.isBanned?&&?user.lastActivityAt?>=?weekAgo).map(user?=>?<li?key={user.id}><img?src={user.avatarUrl}?/><p>{user.fullName}</p><small>{user.role}</small></li>)}</ul>????)
}

這個組件雖然代碼不多,但是做了很多事情:獲取數據、過濾數據、渲染數據。來看看如何分解它。

首先,只要同時使用了 ?useState? 和 ?useEffect,就可以將它們提取到自定義 Hook 中:

const?useUsers?=?()?=>?{const?[users,?setUsers]?=?useState([])useEffect(()?=>?{const?loadUsers?=?async?()?=>?{??const?response?=?await?fetch('/some-api')const?data?=?await?response.json()setUsers(data)}loadUsers()},?[])return?{?users?}
}const?ActiveUsersList?=?()?=>?{const?{?users?}?=?useUsers()const?weekAgo?=?new?Date()weekAgo.setDate(weekAgo.getDate()?-?7)return?(<ul>{users.filter(user?=>?!user.isBanned?&&?user.lastActivityAt?>=?weekAgo).map(user?=>?<li?key={user.id}><img?src={user.avatarUrl}?/><p>{user.fullName}</p><small>{user.role}</small></li>)}</ul>????)
}

現在,useUsers?Hook 只關心一件事——從 API 獲取用戶。它使我們的組件代碼更具可讀性。

接下來看一下組件渲染的 JSX。每當我們對對象數組進行遍歷時,都應該注意它為每個數組項生成的 JSX 的復雜性。如果它是一個沒有附加任何事件處理函數的單行代碼,將其保持內聯是完全沒有問題的。但對于更復雜的 JSX,將其提取到單獨的組件中可能是一個更好的主意:

const?UserItem?=?({?user?})?=>?{return?(<li><img?src={user.avatarUrl}?/><p>{user.fullName}</p><small>{user.role}</small></li>)
}const?ActiveUsersList?=?()?=>?{const?{?users?}?=?useUsers()const?weekAgo?=?new?Date()weekAgo.setDate(weekAgo.getDate()?-?7)return?(<ul>{users.filter(user?=>?!user.isBanned?&&?user.lastActivityAt?>=?weekAgo).map(user?=>?<UserItem?key={user.id}?user={user}?/>)}</ul>????)
}

這里將用于呈現用戶信息的邏輯提取到了一個單獨的組件中,從而使我們的組件更小、更可讀。

最后,從 API 獲取到的用戶列表中過濾出所有非活躍用戶的邏輯是相對獨立的,可以在其他部分重用,所以可以將其提取到一個公共函數中:

const?getOnlyActive?=?(users)?=>?{const?weekAgo?=?new?Date()weekAgo.setDate(weekAgo.getDate()?-?7)return?users.filter(user?=>?!user.isBanned?&&?user.lastActivityAt?>=?weekAgo)
}const?ActiveUsersList?=?()?=>?{const?{?users?}?=?useUsers()return?(<ul>{getOnlyActive(users).map(user?=>?<UserItem?key={user.id}?user={user}?/>)}</ul>????)
}

到現在為止,通過上面三步拆解,組件已經變得比較簡單。但是,仔細觀察會發現,這個組件還有優化的空間。目前,組件首先獲取數據,然后需要對數據進行過濾。理想情況下,我們只想獲取數據并渲染它,而不需要任何額外的操作。所以,可以將這個邏輯封裝到一個新的自定義 Hook 中,最終的代碼如下:

//?獲取數據
const?useUsers?=?()?=>?{const?[users,?setUsers]?=?useState([])useEffect(()?=>?{const?loadUsers?=?async?()?=>?{??const?response?=?await?fetch('/some-api')const?data?=?await?response.json()setUsers(data)}loadUsers()},?[])return?{?users?}
}//?列表渲染
const?UserItem?=?({?user?})?=>?{return?(<li><img?src={user.avatarUrl}?/><p>{user.fullName}</p><small>{user.role}</small></li>)
}//?列表過濾
const?getOnlyActive?=?(users)?=>?{const?weekAgo?=?new?Date()weekAgo.setDate(weekAgo.getDate()?-?7)return?users.filter(user?=>?!user.isBanned?&&?user.lastActivityAt?>=?weekAgo)
}const?useActiveUsers?=?()?=>?{const?{?users?}?=?useUsers()const?activeUsers?=?useMemo(()?=>?{return?getOnlyActive(users)},?[users])return?{?activeUsers?}
}const?ActiveUsersList?=?()?=>?{const?{?activeUsers?}?=?useActiveUsers()return?(<ul>{activeUsers.map(user?=>?<UserItem?key={user.id}?user={user}?/>)}</ul>????)
}

在這里,我們創建了useActiveUsers?Hook 來處理獲取和過濾數據的邏輯,而組件只做了最少的事情——渲染它從 Hook 中獲取的數據。

現在,這個組件只剩下兩個職責:獲取數據渲染數據,當然我們也可以在組件的父級獲取數據,并通過 props 傳入該組件,這樣只需要渲染組件就可以了。當然,還是要視情況而定。我們可以簡單地將獲取并渲染數據看作是“一件事”。

總結

使用單一職責原則可以獲得以下好處:

  1. 提高可維護性:將組件分解為小的職責模塊,使其更易于理解和修改。當需要更新或修復特定功能時,可以更快地定位和處理相關代碼。

  2. 提高復用性:通過將職責分離為獨立的模塊,可以更好地重用組件的不同部分。這樣可以減少重復代碼,提高開發效率。

  3. 降低代碼耦合:職責分離使得組件之間的依賴關系更清晰。當一個組件只關注一個職責時,它變得更加獨立,減少了與其他組件的耦合性。

通過應用單一職責原則,我們可以優化 React 組件的設計,提高其可維護性和復用性。將組件分解為小的職責模塊,提取可復用的功能,保持組件的簡潔和獨立性,使用高階組件和自定義鉤子等技術,都是實現單一職責原則的有效方法。

總而言之,遵循單一職責原則,我們有效地采用了大量獨立的代碼并使其更加模塊化,模塊化的代碼更容易測試和維護。

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

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

相關文章

css網格布局Grid

一、網格布局適應場景 當涉及到的布局是二維布局&#xff08;元素不止一行或者一列&#xff09;且比較復雜的時候&#xff0c;可以用網格布局&#xff0c;看下面的一個例子&#xff1a; 上圖上一個四行三列的網格&#xff0c;布局相對比較復雜。如果你用別的布局方案&#xff…

利用Python生成Xilinx FPGA ROM IP核 .coe初始化文件

以下是一個 Python 腳本&#xff0c;用于生成 Xilinx IP ROM 的.coe 格式初始化文件&#xff0c;假設ROM 深度為 1024&#xff0c;數據位寬為 32bit&#xff0c;使用隨機的 32 位無符號數進行初始化&#xff1a; import random# 定義ROM的深度和數據位寬 rom_depth 1024 data…

8.2 段落格式

在word里&#xff0c;段落格式包括首行縮進、行間距、段前、段后等。LaTex同樣支持這些功能。 段落間距 全局設置 段落間距用setlength命令來指定。如以下代碼 \documentclass{article} \usepackage{ctex} \begin{document}\setlength{\parskip}{11em plus 1em minus 1em}\p…

OpenVLA-OFT

TL;DR 2025 年斯坦福提出的 OpenVLA 工作的續作 OpenVLA-OFT&#xff0c;優化 VLA 能夠有效適應新的機器人平臺和任務&#xff0c;優化的技術主要有并行解碼、動作塊處理、連續動作、L1 回歸和&#xff08;可選的&#xff09;FiLM 語言調節 Paper name Fine-Tuning Vision-La…

SpringBoot 接口國際化i18n 多語言返回 中英文切換 全球化 語言切換

介紹 Spring Boot通過MessageSource接口來實現國際化&#xff0c;它可以加載不同的消息資源文件&#xff0c;通常是.properties格式。通過定義不同的語言文件&#xff08;例如&#xff1a;messages_en.properties、messages_zh.properties等&#xff09;&#xff0c;可以根據用…

一個crackme例子

文件下載地址&#xff1a;https://download.csdn.net/download/m0_37567738/90713354 將cipher.txt文件內容解密后&#xff1a; 恭喜你解出了這一關&#xff0c;flag為 zjwa{36_23121136a28d0d15} 好了現在告訴你最后一層的獲取方式&#xff0c; 在系統內找到 手機鏡像的 ra…

賬戶解封無望?3步高效申訴取回亞馬遜凍結資金

近年來&#xff0c;隨著全球跨境電商市場的飛速擴張&#xff0c;亞馬遜&#xff08;Amazon&#xff09;作為其中的巨頭&#xff0c;持續強化其平臺治理力度。然而&#xff0c;隨之而來的是賣家賬戶因各種原因被凍結、關閉的事件頻頻發生。根據Marketplace Pulse發布的2024年第一…

【C++ Qt】快速上手 顯?類控件(Label、LCDNumber、ProcessBar、CalendarWidget)

每日激勵&#xff1a;“不設限和自我肯定的心態&#xff1a;I can do all things。 — Stephen Curry” 緒論?&#xff1a; 本文圍繞Qt中常用的顯示類控件展開&#xff0c;重點講解了 QLabel&#xff08;文本/圖片顯示&#xff09;、QLCDNumber&#xff08;數字顯示&#xff0…

從困局到破局的AI+數據分析

從困局到破局的AI數據分析 困局&#xff1a;數據分析的四道高墻破局&#xff1a;AI賦能全流程數據分析遠見&#xff1a;AI數據分析的革命性意義 數據是新時代的石油&#xff0c;人工智能是煉油廠。當兩者強強聯合&#xff0c;一場數據分析的革命正悄然發生。 多少次你面對Excel…

IGH 匯川SV660N調試

EoE 目前的方式是將eoe 關閉, 這需要重新配置編譯ec_master sudo ./configure --disable-8139too --enable-generic --enable-r8169 --disable-eoe --enable-coe[426163.348589] EtherCAT 0: Master thread exited. [426163.348592] EtherCAT 0: Stopping EoE thread. [426163.…

Java基礎361問第16問——枚舉為什么導致空指針?

我們看一段代碼 public enum Color {RED, BLUE, YELLOW;public static Color parse(String color) {return null;} }public static void main() {Color color Color.parse("");// 極具迷惑性&#xff0c;大家日常開發肯定這么寫過switch (color) {case RED:break;c…

10.Excel:快速定位目標值

一 批量刪除 1.如何使用 快捷鍵 CTRLG 補充&#xff1a;直接選擇定位條件。 2.作用 1.批量刪除工作表中的圖片 補充&#xff1a;無法通過框選的方式選中這些圖片進行刪除。 這樣只框選了表格&#xff0c;無法框選圖片。因為圖片在excel中被認為是一個對象&#xff0c;對象無法通…

快樂數(雙指針解法)

題目鏈接202. 快樂數 - 力扣&#xff08;LeetCode&#xff09; 題目拆解 1 取一個正整數每一位的平方和為&#xff0c;如果為1那么直接可以判定為快樂數&#xff0c;如果不為1&#xff0c;就重復這個過程&#xff0c;直到出現1 2 實際上&#xff0c;這道題只有兩種情況&#xf…

進程控制的學習

進程控制&#xff08;Process Control&#xff09;是指操作系統對進程的創建、執行、暫停、恢復、終止等一系列狀態變化進行管理和協調的過程。 簡單說&#xff0c;就是系統讓各個程序能有序地運行&#xff0c;合理地使用CPU和資源&#xff0c;而不會互相沖突或者出錯。 主要包…

818協議知識筆記

一、概念 Fibre CHannel-Audio Vedio standard;FC-AV FC-FS:Fibre channel framing and signaling interface; FC-PI:fibre channel physical interfaces 二、術語 VGA,SVGA,XGA,WXGA,SXGA,SXGA,WSXGA,UXGA,1440P; ICD:interface control document接口控制文檔 CRC對幀頭和數據…

AI大模型學習十二:?嘗鮮ubuntu 25.04 桌面版私有化sealos cloud + devbox+minio對象存儲測試和漫長修改之路

一、說明 前面已經安裝完成&#xff0c;這里我們測試對象存儲 AI大模型學習十一&#xff1a;?嘗鮮ubuntu 25.04 桌面版私有化sealos cloud devboxminio&#xff0c;實戰運行成功-CSDN博客https://blog.csdn.net/jiangkp/article/details/147424823?spm1011.2415.3001.5331 二…

SpringBoot的自動掃描特性-筆記

1.Spring Boot 的自動掃描特性介紹 Spring Boot 的自動掃描&#xff08;Component Scanning&#xff09;是其核心特性之一。通過注解SpringBootApplication 簡化了 Bean 的管理&#xff0c;允許框架自動發現并注冊帶有特定注解的類為 Spring 容器中的 Bean&#xff08;特定注解…

基于nodeJS代碼的通過爬蟲方式實現tiktok發布視頻(2025年4月)

1、將真實的tiktokstudio平臺的cookie填到代碼里的cookie變量里,修改python代碼里的ticket,ts, privateKey,以及videoPath,timing等變量的值,最后運行python腳本即可; 2、運行之前根據import提示安裝一些常見依賴,比如node-fetch等; 3、運行時候可能系統需要科學上網…

數據一致性問題剖析與實踐(四)——競態條件競爭導致的一致性問題

一、前言 之前我們討論了幾種場景的一致性問題 冗余數據存儲中的一致性問題分布式共識中的一致性問題單機事務中的一致性問題分布式事務中的一致性問題 本文將圍繞競態條件競爭中的一致性問題展開討論分析。 二、 問題定義 競態條件&#xff08;Race Condition&#xff09…

PCL點云處理之基于FPFH特征的SAC-IA全局配準算法 (二百四十六)

提示: 有相關點云需求的可以私信 PCL 點云處理之基于 FPFH 特征的 SAC - IA 全局配準算法 一、前言二、相關概念介紹2.1 點云2.2 FPFH 特征2.3 SAC - IA 算法三、SAC - IA 全局配準算法原理3.1 FPFH 特征提取3.2 SAC - IA 配準過程四、代碼實現與分析4.1 完整代碼4.2 代碼分析…