我時常會聽到人們談起React函數元件,提到函數元件會不可避免的變得體積更大,邏輯更複雜。畢竟,我們把元件寫在了「一個函數」裡,因此你不得不接受元件會膨脹導致這個函數會不斷膨脹。 React的元件中也有提到:
既然函數元件能做的事情越來越多,那麼你的程式碼庫中的函式元件整體上看會越來越長。 【相關推薦:Redis影片教學、程式影片】
#其中也提到我們應該:
盡量避免過早加入抽象
如果你使用CodeScene,你可能會注意到它會在你的函數太長或太複雜的時候對你提示警告。如果按照我們之前所說的,我們可能會考慮是不是應該將CodeScene相關警告配置的更加廣泛一些。當然這是完全可以做到的,但是我覺得我們不應該這麼做,我們也不應該拒絕在程式碼中添加許多的抽象,我們可以從中獲取到很多的好處,並且大多數時候我們花費的成本並不高。我們可以繼續將我們的程式碼健康度保持的非常好!
處理複雜性
我們應該要意識到,雖然函數元件被寫在「一個函數」裡,但是這個函數仍然可以像別的函數一樣,可以由許多其他函數組成的。像useState
,useEffect
,抑或是別的hooks,子元件它們本身也是個函數。因此我們自然可以利用相同的思路來處理函數元件的複雜性問題:透過建立一個新函數,來把即符合公共模式又複雜的程式碼封裝起來。
比較常見的處理複雜組件的方式是把它分解成多個子組件。但是這麼做可能會讓人覺得不自然或很難準確的去描述這些子組件。這時候我們就可以藉助梳理元件的鉤子函數的邏輯來發現新的抽象點。
每當我們在元件內看到由useState
、useEffect
或是其他內建鉤子函數組成的長長的清單時,我們就應該去考慮是否可以將它們提取到一個自訂hook中去。自訂hook函數是一種可以在其內部使用其他鉤子函數的函數,並且建立自訂鉤子函數也很簡單。
如下所示的元件相當於一個看板,用一個清單展示一個使用者倉庫的資料(想像成和github類似的)。這個元件並不算是個複雜元件,但是它是展示如何應用自訂hook的一個不錯的例子。
function Dashboard() { const [repos, setRepos] = useState<Repo[]>([]); const [isLoadingRepos, setIsLoadingRepos] = useState(true); const [repoError, setRepoError] = useState<string | null>(null); useEffect(() => { fetchRepos() .then((p) => setRepos(p)) .catch((err) => setRepoError(err)) .finally(() => setIsLoadingRepos(false)); }, []); return ( <div className="flex gap-2 mb-8"> {isLoadingRepos && <Spinner />} {repoError && <span>{repoError}</span>} {repos.map((r) => ( <RepoCard key={i.name} item={r} /> ))} </div> ); }
我們要把鉤子邏輯提取到一個自訂hook中,我們只需要把這些程式碼複製到一個以use
開頭的函數中(在這裡我們將其命名為useRepos
):
/** * 请求所有仓库用户列表的hook函数 */ export function useRepos() { const [repos, setRepos] = useState<Repo[]>([]); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState<string | null>(null); useEffect(() => { fetchRepos() .then((p) => setRepos(p)) .catch((err) => setError(err)) .finally(() => setIsLoading(false)); }, []); return [repos, isLoading, error] as const; }
必須用use
開頭的原因是linter
外掛可以偵測到你目前建立的是鉤子函數而不是普通函數,這樣插件就可以檢查你的鉤子函數是否符合正確的自訂鉤子的相關規則。
比較提煉之前,提煉後出現的新東西只有回傳語句和as const
。這裡的類型提示只是為了確保類型推論是正確的:一個包含3個元素的數組,類型分別是Repo[], boolean, string | null
。當然,你可以從鉤子函數返回任何你希望返回的東西。
譯者註:這裡加上
as const
在ts型別推論的差異主要體現在數字元素的個數。不加入as const
,推論的型別為(string | boolean | Repo[] | null)[]
,新增後的型別推論為readonly [Repo[], boolean, string | null]
。
將自訂鉤子useRepos
應用在我們的元件中,程式碼變成了:
function Dashboard() { const [repos, isLoadingRepos, repoError] = useRepos(); return ( <div className="flex gap-2 mb-8"> {isLoadingRepos && <Spinner />} {repoError && <span>{repoError}</span>} {repos.map((i) => ( <RepoCard key={i.name} item={i} /> ))} </div> ); }
可以發現,我們現在無法在元件內部呼叫任何的setter
函數,即無法改變狀態。在這個元件我們已經不需要包含修改狀態的邏輯,這些邏輯都包含在了useRepos
鉤子函數中。當然如果你確實需要它們,你也可以在鉤子函數的回傳語句中將其暴露出來。
這麼做有什麼好處呢? React的文檔中有提到:
透過提取自訂鉤子函數,可以實現元件邏輯的複用
我們可以簡單的想像一下,如果這個應用程式中的別的元件也需要展示倉庫中的使用者列表,那麼這個元件需要做的就只有導入useRepos
鉤子函式。如果鉤子更新了,可能使用某種形式的緩存,或者透過輪詢或更複雜的方法進行持續更新,那麼引用了這個鉤子的所有元件都將受益。
當然,提取自訂鉤子除了可以方便復用外,還有別的好處。在我們的例子中,所有的useState
和useEffect
都是為了實現同一個功能——就是獲取庫用戶列表,我們把這個看作一個原子功能,那麼在一個組件中,包含很多個這樣的原子功能也是很常見的。如果我們把這些原子功能的程式碼都分別提取到不同的自訂鉤子函數中,就更容易發現哪些狀態在我們修改程式碼邏輯時要保持同步更新,不容易出現遺漏的情況。除此之外,這麼做的好處還有:
- 越短小的函數越容易看懂
- #為原子功能命名的能力(如useRepo)
- #更自然的提供文件說明(每個自訂鉤子函數的功能比較內聚單一,這種函數也很容易去寫註解)
最後
我們已經了解到React的鉤子函數並沒有多麼神秘,也和其他函數一樣很容易就可以創建。我們可以創建自己的領域特定的鉤子,進而在整個應用程式中重複使用。也可以在各種部落格或「鉤子庫」中找到許多預先編寫好的通用鉤子。這些鉤子可以想useState
和useEffect
一樣很方便的在我們的專案中應用。 Dan Abramov的useInterval
鉤子就是一個例子,例如你有一個類似useRepos
的鉤子,但是你需要可以輪詢更新?那你就可以嘗試在你的鉤子中使用useInterval
。
英文原文網址:https://codescene.com/engineering-blog/refactoring-components-in-react-with-custom-hooks
#【推薦學習:javascript影片教學】
#以上是【翻譯】使用自訂hooks對React元件進行重構的詳細內容。更多資訊請關注PHP中文網其他相關文章!

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。1.Python以简洁语法和丰富库生态著称,适用于数据分析和Web开发。2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

JavaScript不需要安裝,因為它已內置於現代瀏覽器中。你只需文本編輯器和瀏覽器即可開始使用。 1)在瀏覽器環境中,通過標籤嵌入HTML文件中運行。 2)在Node.js環境中,下載並安裝Node.js後,通過命令行運行JavaScript文件。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Dreamweaver CS6
視覺化網頁開發工具

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境

SublimeText3 Linux新版
SublimeText3 Linux最新版