教你應(yīng)用?SOLID?原則整理?React?代碼之單一原則
SOLID 原則的主要是作為關(guān)心自己工作的軟件專業(yè)人員的指導(dǎo)方針,那些以經(jīng)得起時間考驗的設(shè)計精美的代碼庫為榮的人。
今天,我們將從一個糟糕的代碼示例開始,應(yīng)用 SOLID 的第一個原則,看看它如何幫助我們編寫小巧、漂亮、干凈的并明確責(zé)任的 React 組件,。
什么是單一責(zé)任原則?
單一責(zé)任原則告訴我們的是,每個類或組件應(yīng)該有一個單一的存在目的。
組件應(yīng)該只做一件事,并且做得很好。
讓我們重構(gòu)一段糟糕但正常工作的代碼,并使用這個原則使其更加清晰和完善。
讓我們從一個糟糕的例子開始
首先讓我們看看一些違反這一原則的代碼,添加注釋是為了更好地理解:
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) ????} ????//?遠程數(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> ????????})} ????</> }
這段代碼的作用
這是一個函數(shù)式組件,我們從遠程數(shù)據(jù)源獲取數(shù)據(jù),再過濾數(shù)據(jù),然后在 UI 中顯示數(shù)據(jù)。我們還檢測 API 調(diào)用的加載狀態(tài)。
為了更好地理解這個例子,我把它簡化了。但是你幾乎可以在任何地方的同一個組件中找到它們!這里發(fā)生了很多事情:
遠程數(shù)據(jù)的獲取
數(shù)據(jù)過濾
復(fù)雜的狀態(tài)管理
復(fù)雜的 UI 功能
因此,讓我們探索如何改進代碼的設(shè)計并使其緊湊。
1. 移動數(shù)據(jù)處理邏輯
不要將 HTTP 調(diào)用保留在組件中。這是經(jīng)驗之談。您可以采用幾種策略從組件中刪除這些代碼。
您至少應(yīng)該創(chuàng)建一個自定義 Hook 并將數(shù)據(jù)獲取邏輯移動到那里。例如,我們可以創(chuàng)建一個名為 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)在我們的主要組件看起來像這樣:
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)在是多么的小,多么的容易理解!這是在錯綜復(fù)雜的代碼庫中所能做的最簡單、最重要的事情。
但我們可以做得更好。
2. 可重用的數(shù)據(jù)獲取鉤子
現(xiàn)在,當我們看到我們 useGetRemoteData
Hook 時,我們看到這個 Hook 正在做兩件事:
從遠程數(shù)據(jù)源獲取數(shù)據(jù)
過濾數(shù)據(jù)
讓我們把獲取遠程數(shù)據(jù)的邏輯提取到一個單獨的鉤子,這個鉤子的名字是 useHttpGetRequest
,它把 URL 作為一個參數(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 邏輯移除到一個單獨的文件中:
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} }
干凈多了,對吧? 我們能做得更好嗎? 當然,為什么不呢?
3. 分解 UI 組件
看看我們的組件,其中顯示了用戶的詳細信息。我們可以為此創(chuàng)建一個可重用的 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 行精簡到了 12 行!我們創(chuàng)建了五個獨立的組成部分,每個部分都有明確而單一的職責(zé)。
讓我們回顧一下我們剛剛做了什么
讓我們回顧一下我們的組件,看看我們是否實現(xiàn)了 SRP:
Users.js
- 負責(zé)顯示用戶列表UserDetails.js
ー 負責(zé)顯示用戶的詳細資料useGetRemoteData.js
- 負責(zé)過濾遠程數(shù)據(jù)useHttpGetrequest.js
- 負責(zé) HTTP 調(diào)用LoadingReducer.js
- 復(fù)雜的狀態(tài)管理
當然,我們可以改進很多其他的東西,但是這應(yīng)該是一個很好的起點。
總結(jié)
這是一個簡單的演示,演示如何減少每個文件中的代碼量,并使用 SOLID 的強大功能創(chuàng)建漂亮的可重用組件。
到此這篇關(guān)于如何應(yīng)用 SOLID 原則整理 React 代碼之單一原則的文章就介紹到這了,更多相關(guān)React SOLID單一原則內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
react使用axios進行api網(wǎng)絡(luò)請求的封裝方法詳解
這篇文章主要為大家詳細介紹了react使用axios進行api網(wǎng)絡(luò)請求的封裝方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-03-03React組件實例三大屬性state props refs使用詳解
這篇文章主要為大家介紹了React組件實例三大屬性state props refs使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-09-09react-router v4如何使用history控制路由跳轉(zhuǎn)詳解
這篇文章主要給大家介紹了關(guān)于react-router v4如何使用history控制路由跳轉(zhuǎn)的相關(guān)資料,文中通過示例代碼介紹的的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01Remix集成antd和pro-components的過程示例
這篇文章主要為大家介紹了Remix集成antd和pro-components的過程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03解決react-connect中使用forwardRef遇到的問題
這篇文章主要介紹了解決react-connect中使用forwardRef遇到的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-05-05React-Native之TextInput組件的設(shè)置以及如何獲取輸入框的內(nèi)容
這篇文章主要介紹了React-Native之TextInput組件的設(shè)置以及如何獲取輸入框的內(nèi)容問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-05-05