您好,登錄后才能下訂單哦!
這篇文章主要介紹了如何使用自定義hooks對React組件進行重構的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇如何使用自定義hooks對React組件進行重構文章都會有所收獲,下面我們一起來看看吧。
我們應該要意識到,雖然函數組件被寫在“一個函數”里,但是這個函數仍然可以像別的函數一樣,可以由許多其他函數組成的。像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)
更自然的提供文檔說明(每個自定義鉤子函數的功能更加內聚單一,這種函數也很容易去寫注釋
關于“如何使用自定義hooks對React組件進行重構”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“如何使用自定義hooks對React組件進行重構”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。