【翻譯】使用自訂hooks對React元件進行重構
我時常會聽到人們談起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中文網其他相關文章!

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

PHP與Vue:完美搭檔的前端開發利器在當今網路快速發展的時代,前端開發變得愈發重要。隨著使用者對網站和應用的體驗要求越來越高,前端開發人員需要使用更有效率和靈活的工具來創建響應式和互動式的介面。 PHP和Vue.js作為前端開發領域的兩個重要技術,搭配起來可以稱得上是完美的利器。本文將探討PHP和Vue的結合,以及詳細的程式碼範例,幫助讀者更好地理解和應用這兩

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

Django是一個由Python編寫的web應用框架,它強調快速開發和乾淨方法。儘管Django是web框架,但要回答Django是前端還是後端這個問題,需要深入理解前後端的概念。前端是指使用者直接和互動的介面,後端是指伺服器端的程序,他們透過HTTP協定進行資料的互動。在前端和後端分離的情況下,前後端程式可以獨立開發,分別實現業務邏輯和互動效果,資料的交

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

Go語言作為一種快速、高效的程式語言,在後端開發領域廣受歡迎。然而,很少有人將Go語言與前端開發聯繫起來。事實上,使用Go語言進行前端開發不僅可以提高效率,還能為開發者帶來全新的視野。本文將探討使用Go語言進行前端開發的可能性,並提供具體的程式碼範例,幫助讀者更了解這一領域。在傳統的前端開發中,通常會使用JavaScript、HTML和CSS來建立使用者介面

Django:前端和後端開發都能搞定的神奇框架! Django是一個高效、可擴展的網路應用程式框架。它能夠支援多種Web開發模式,包括MVC和MTV,可以輕鬆地開發出高品質的Web應用程式。 Django不僅支援後端開發,還能夠快速建構出前端的介面,透過模板語言,實現靈活的視圖展示。 Django把前端開發和後端開發融合成了一種無縫的整合,讓開發人員不必專門學習

在前端開發面試中,常見問題涵蓋廣泛,包括HTML/CSS基礎、JavaScript基礎、框架和函式庫、專案經驗、演算法和資料結構、效能最佳化、跨域請求、前端工程化、設計模式以及新技術和趨勢。面試官的問題旨在評估候選人的技術技能、專案經驗以及對行業趨勢的理解。因此,應試者應充分準備這些方面,以展現自己的能力和專業知識。
