網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
SOLID 原則的主要是作為關(guān)心自己工作的軟件專(zhuān)業(yè)人員的指導(dǎo)方針,那些以經(jīng)得起時(shí)間考驗(yàn)的設(shè)計(jì)精美的代碼庫(kù)為榮的人。
今天,我們將從一個(gè)糟糕的代碼示例開(kāi)始,應(yīng)用 SOLID 的第一個(gè)原則,看看它如何幫助我們編寫(xiě)小巧、漂亮、干凈的并明確責(zé)任的 React 組件,。
什么是單一責(zé)任原則?
單一責(zé)任原則告訴我們的是,每個(gè)類(lèi)或組件應(yīng)該有一個(gè)單一的存在目的。
組件應(yīng)該只做一件事,并且做得很好。
讓我們重構(gòu)一段糟糕但正常工作的代碼,并使用這個(gè)原則使其更加清晰和完善。
讓我們從一個(gè)糟糕的例子開(kāi)始
首先讓我們看看一些違反這一原則的代碼,添加注釋是為了更好地理解:
import?React,?{useEffect,?useReducer,?useState}?from?"react"; const?initialState?=?{ ????isLoading:?true }; //?復(fù)雜的狀態(tài)管理 function?reducer(state,?action)?{ ????switch?(action.type)?{ ????????case?'LOADING': ????????????return?{isLoading:?true}; ????????case?'FINISHED': ????????????return?{isLoading:?false}; ????????default: ????????????return?state; ????} } export?const?SingleResponsibilityPrinciple?=?()?=>?{ ????const?[users?,?setUsers]?=?useState([]) ????const?[filteredUsers?,?setFilteredUsers]?=?useState([]) ????const?[state,?dispatch]?=?useReducer(reducer,?initialState); ????const?showDetails?=?(userId)?=>?{ ????????const?user?=?filteredUsers.find(user?=>?user.id===userId); ????????alert(user.contact) ????} ????//?遠(yuǎn)程數(shù)據(jù)獲取 ????useEffect(()?=>?{ ????????dispatch({type:'LOADING'}) ????????fetch('https://jsonplaceholder.typicode.com/users') ????????????.then(response?=>?response.json()) ????????????.then(json?=>?{ ????????????????dispatch({type:'FINISHED'}) ????????????????setUsers(json) ????????????}) ????},[]) ????//?數(shù)據(jù)處理 ????useEffect(()?=>?{ ????????const?filteredUsers?=?users.map(user?=>?{ ????????????return?{ ????????????????id:?user.id, ????????????????name:?user.name, ????????????????contact:?`${user.phone}?,?${user.email}` ????????????}; ????????}); ????????setFilteredUsers(filteredUsers) ????},[users]) ????//?復(fù)雜UI渲染 ????return?<> ????????<div>?Users?List</div> ????????<div>?Loading?state:?{state.isLoading??'Loading':?'Success'}</div> ????????{users.map(user?=>?{ ????????????return?<div?key={user.id}?onClick={()?=>?showDetails(user.id)}> ????????????????<div>{user.name}</div> ????????????????<div>{user.email}</div> ????????????</div> ????????})} ????</> }
這段代碼的作用
這是一個(gè)函數(shù)式組件,我們從遠(yuǎn)程數(shù)據(jù)源獲取數(shù)據(jù),再過(guò)濾數(shù)據(jù),然后在 UI 中顯示數(shù)據(jù)。我們還檢測(cè) API 調(diào)用的加載狀態(tài)。
為了更好地理解這個(gè)例子,我把它簡(jiǎn)化了。但是你幾乎可以在任何地方的同一個(gè)組件中找到它們!這里發(fā)生了很多事情:
遠(yuǎn)程數(shù)據(jù)的獲取
數(shù)據(jù)過(guò)濾
復(fù)雜的狀態(tài)管理
復(fù)雜的 UI 功能
因此,讓我們探索如何改進(jìn)代碼的設(shè)計(jì)并使其緊湊。
1. 移動(dòng)數(shù)據(jù)處理邏輯
不要將 HTTP 調(diào)用保留在組件中。這是經(jīng)驗(yàn)之談。您可以采用幾種策略從組件中刪除這些代碼。
您至少應(yīng)該創(chuàng)建一個(gè)自定義 Hook 并將數(shù)據(jù)獲取邏輯移動(dòng)到那里。例如,我們可以創(chuàng)建一個(gè)名為?useGetRemoteData
?的 Hook,如下所示:
import?{useEffect,?useReducer,?useState}?from?"react"; const?initialState?=?{ ????isLoading:?true }; function?reducer(state,?action)?{ ????switch?(action.type)?{ ????????case?'LOADING': ????????????return?{isLoading:?true}; ????????case?'FINISHED': ????????????return?{isLoading:?false}; ????????default: ????????????return?state; ????} } export?const?useGetRemoteData?=?(url)?=>?{ ????const?[users?,?setUsers]?=?useState([]) ????const?[state,?dispatch]?=?useReducer(reducer,?initialState); ????const?[filteredUsers?,?setFilteredUsers]?=?useState([]) ????useEffect(()?=>?{ ????????dispatch({type:'LOADING'}) ????????fetch('https://jsonplaceholder.typicode.com/users') ????????????.then(response?=>?response.json()) ????????????.then(json?=>?{ ????????????????dispatch({type:'FINISHED'}) ????????????????setUsers(json) ????????????}) ????},[]) ????useEffect(()?=>?{ ????????const?filteredUsers?=?users.map(user?=>?{ ????????????return?{ ????????????????id:?user.id, ????????????????name:?user.name, ????????????????contact:?`${user.phone}?,?${user.email}` ????????????}; ????????}); ????????setFilteredUsers(filteredUsers) ????},[users]) ????return?{filteredUsers?,?isLoading:?state.isLoading} }
現(xiàn)在我們的主要組件看起來(lái)像這樣:
import?React?from?"react"; import?{useGetRemoteData}?from?"./useGetRemoteData"; export?const?SingleResponsibilityPrinciple?=?()?=>?{ ????const?{filteredUsers?,?isLoading}?=?useGetRemoteData() ????const?showDetails?=?(userId)?=>?{ ????????const?user?=?filteredUsers.find(user?=>?user.id===userId); ????????alert(user.contact) ????} ????return?<> ????????<div>?Users?List</div> ????????<div>?Loading?state:?{isLoading??'Loading':?'Success'}</div> ????????{filteredUsers.map(user?=>?{ ????????????return?<div?key={user.id}?onClick={()?=>?showDetails(user.id)}> ????????????????<div>{user.name}</div> ????????????????<div>{user.email}</div> ????????????</div> ????????})} ????</> }
看看我們的組件現(xiàn)在是多么的小,多么的容易理解!這是在錯(cuò)綜復(fù)雜的代碼庫(kù)中所能做的最簡(jiǎn)單、最重要的事情。
但我們可以做得更好。
2. 可重用的數(shù)據(jù)獲取鉤子
現(xiàn)在,當(dāng)我們看到我們?useGetRemoteData
?Hook 時(shí),我們看到這個(gè) Hook 正在做兩件事:
從遠(yuǎn)程數(shù)據(jù)源獲取數(shù)據(jù)
過(guò)濾數(shù)據(jù)
讓我們把獲取遠(yuǎn)程數(shù)據(jù)的邏輯提取到一個(gè)單獨(dú)的鉤子,這個(gè)鉤子的名字是?useHttpGetRequest
,它把 URL 作為一個(gè)參數(shù):
import?{useEffect,?useReducer,?useState}?from?"react"; import?{loadingReducer}?from?"./LoadingReducer"; const?initialState?=?{ ????isLoading:?true }; export?const?useHttpGetRequest?=?(URL)?=>?{ ????const?[users?,?setUsers]?=?useState([]) ????const?[state,?dispatch]?=?useReducer(loadingReducer,?initialState); ????useEffect(()?=>?{ ????????dispatch({type:'LOADING'}) ????????fetch(URL) ????????????.then(response?=>?response.json()) ????????????.then(json?=>?{ ????????????????dispatch({type:'FINISHED'}) ????????????????setUsers(json) ????????????}) ????},[]) ????return?{users?,?isLoading:?state.isLoading} }
我們還將 reducer 邏輯移除到一個(gè)單獨(dú)的文件中:
export?function?loadingReducer(state,?action)?{ ????switch?(action.type)?{ ????????case?'LOADING': ????????????return?{isLoading:?true}; ????????case?'FINISHED': ????????????return?{isLoading:?false}; ????????default: ????????????return?state; ????} }
所以現(xiàn)在我們的?useGetRemoteData
?變成了:
import?{useEffect,?useState}?from?"react"; import?{useHttpGetRequest}?from?"./useHttpGet"; const?REMOTE_URL?=?'https://jsonplaceholder.typicode.com/users' export?const?useGetRemoteData?=?()?=>?{ ????const?{users?,?isLoading}?=?useHttpGetRequest(REMOTE_URL) ????const?[filteredUsers?,?setFilteredUsers]?=?useState([]) ????useEffect(()?=>?{ ????????const?filteredUsers?=?users.map(user?=>?{ ????????????return?{ ????????????????id:?user.id, ????????????????name:?user.name, ????????????????contact:?`${user.phone}?,?${user.email}` ????????????}; ????????}); ????????setFilteredUsers(filteredUsers) ????},[users]) ????return?{filteredUsers?,?isLoading} }
干凈多了,對(duì)吧? 我們能做得更好嗎? 當(dāng)然,為什么不呢?
3. 分解 UI 組件
看看我們的組件,其中顯示了用戶(hù)的詳細(xì)信息。我們可以為此創(chuàng)建一個(gè)可重用的 UserDetails 組件:
const?UserDetails?=?(user)?=>?{ ????const?showDetails?=?(user)?=>?{ ????????alert(user.contact) ????} ????return?<div?key={user.id}?onClick={()?=>?showDetails(user)}> ????????<div>{user.name}</div> ????????<div>{user.email}</div> ????</div> }
最后,我們的原始組件變成:
import?React?from?"react"; import?{useGetRemoteData}?from?"./useGetRemoteData"; export?const?Users?=?()?=>?{ ????const?{filteredUsers?,?isLoading}?=?useGetRemoteData() ????return?<> ????????<div>?Users?List</div> ????????<div>?Loading?state:?{isLoading??'Loading':?'Success'}</div> ????????{filteredUsers.map(user?=>?<UserDetails?user={user}/>)} ????</> }
我們把代碼從 60 行精簡(jiǎn)到了 12 行!我們創(chuàng)建了五個(gè)獨(dú)立的組成部分,每個(gè)部分都有明確而單一的職責(zé)。
讓我們回顧一下我們剛剛做了什么
讓我們回顧一下我們的組件,看看我們是否實(shí)現(xiàn)了 SRP:
Users.js
?- 負(fù)責(zé)顯示用戶(hù)列表UserDetails.js
?ー 負(fù)責(zé)顯示用戶(hù)的詳細(xì)資料useGetRemoteData.js
?- 負(fù)責(zé)過(guò)濾遠(yuǎn)程數(shù)據(jù)useHttpGetrequest.js
?- 負(fù)責(zé) HTTP 調(diào)用LoadingReducer.js
?- 復(fù)雜的狀態(tài)管理
當(dāng)然,我們可以改進(jìn)很多其他的東西,但是這應(yīng)該是一個(gè)很好的起點(diǎn)。
總結(jié)
這是一個(gè)簡(jiǎn)單的演示,演示如何減少每個(gè)文件中的代碼量,并使用 SOLID 的強(qiáng)大功能創(chuàng)建漂亮的可重用組件。
原文鏈接:https://mp.weixin.qq.com/s/oOcoy5rJwqH939MIOrgaiA
相關(guān)推薦
- 2022-03-26 正則表達(dá)式詳析+常用示例_正則表達(dá)式
- 2022-06-18 android?ScrollView實(shí)現(xiàn)水平滑動(dòng)回彈_Android
- 2022-04-25 淺談Golang?Slice切片如何擴(kuò)容的實(shí)現(xiàn)_Golang
- 2022-09-24 ASP.NET?MVC下拉框中顯示枚舉項(xiàng)_實(shí)用技巧
- 2022-09-25 uniapp封裝request請(qǐng)求的方法
- 2022-05-02 C++的輸入和輸出流詳解_C 語(yǔ)言
- 2023-01-05 Qt操作SQLite數(shù)據(jù)庫(kù)的教程詳解_C 語(yǔ)言
- 2022-10-22 SQLMAP插件tamper編寫(xiě)與使用詳解_MsSql
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支