什么是自定義hook?
使用自定義hook可以將某些組件邏輯提取到可重用的函數中。
自定義hook是一個從use開始的調用其他hook的Javascript函數。請記住,組件和hook是函數,因此我們在這里實際上并沒有創建任何新概念。我們只是將代碼重構為另一個函數以使其可重用。
不使用自定義hook
假設我們的組件中有一個功能可以檢索窗口的寬度。我們想知道用戶何時調整屏幕大小。我們可以這樣寫:
const LayoutComponent = () => {
const [onSmallScreen, setOnSmallScreen] = useState(false);
useEffect(() => {
checkScreenSize();
window.addEventListener("resize", checkScreenSize);
}, []);
let checkScreenSize = () => {
setOnSmallScreen(window.innerWidth < 768);
};
return (
<div className={`${onSmallScreen ? "small" : "large"}`}>
<h1>Hello World!</h1>
</div>
);
};
我們這里有一個具有onSmallScreen state的組件,該組件知道我們是否在寬度小于768像素的窗口中。要知道這一點,我們使用了useEffecthook。在該hook內,我們首先調用checkScreenSize函數,該函數更新onSmallScreen狀態變量。最后,我們將checkScreenSize函數綁定到調整大小事件偵聽器,以在發生調整大小事件時在必要時更新狀態。
創建自定義hook
這樣很好。窗口的寬度一旦小于600像素,類名稱就會更改為small,而超過600像素時,類名稱會變為large。
現在,假設我想在應用程序的其他位置使用此功能,控制窗口的寬度。我應該復制并粘貼此代碼嗎?我們可以,但是我們可以在自定義hook中提取此功能,并在需要的任何地方重復使用。
因為hook只是Javascript函數,所以它們實際上不需要一個React組件。
我將創建一個名為useWindowWidth.js的新文件:
import { useState, useEffect } from "react";
const useWindowsWidth = () => {
const [isScreenSmall, setIsScreenSmall] = useState(false);
let checkScreenSize = () => {
setIsScreenSmall(window.innerWidth < 600);
};
useEffect(() => {
checkScreenSize();
window.addEventListener("resize", checkScreenSize);
return () => window.removeEventListener("resize", checkScreenSize);
}, []);
return isScreenSmall;
};
export default useWindowsWidth;
我們在useWindowWidth函數中提取了此功能?,F在,我們可以將其導入到要使用的任何位置!
import React from 'react'
import useWindowWidth from './useWindowWidth.js'
const MyComponent = () => {
const onSmallScreen = useWindowWidth();
return (
// Return some elements
)
}
那不是很酷嗎?我在一個項目中擁有其中一種功能。我需要知道窗口的大小才能適應我正在渲染的元素。使用自定義hook可以減少重復代碼的數量。
當然,您可以在組件的hook內部使用的所有內容都可以提取并用于自定義hook。
例如,假設您有一些組件可顯示文章的評論列表。我們可以想象其中的幾行:
const ArticleWithComments = (articleId) => {
const [comments, setComments] = useState([])
const [error, setError] = useState(null)
let handleCommentsSuccessFetch = (articleComments) => setComments(articleComments)
let handleError = error => setError(error)
useEffect(() => {
fetchComments(articleId, handleCommentsSuccessFetch, handleError)
}, [])
return (
// Do something in the DOM
)
}
const BlogPostWithComments = (blogPostId) => {
const [comments, setComments] = useState([])
const [error, setError] = useState(null)
let handleCommentsSuccessFetch = (blogPostComments) => setComments(blogPostComments)
let handleError = error => setError(error)
useEffect(() => {
fetchComments(blogPostId, handleCommentsSuccessFetch, handleError)
}, [])
return (
// Do something in the DOM
)
}
在這個例子中,我們有兩個組成部分。他們倆都根據ID(文章ID或博客文章ID)獲取評論列表。在useEffect hook中,我們有一個API調用,可通過兩個函數檢索這些注釋。一個在成功的情況下將狀態設置為注釋,第二個在錯誤的情況下將狀態設置為錯誤。
但是,功能在這兩個組件之間是重復的。幸運的是,我們可以在自定義hook中提取此功能:
const useCommentsRetriever = (entityId) => {
const [comments, setComments] = useState([]);
const [error, setError] = useState(null);
let handleCommentsSuccessFetch = (comments) => setComments(comments);
let handleError = (error) => setError(error);
useEffect(() => {
fetchComments(entityId, handleCommentsSuccessFetch, handleError);
}, []);
return [comments, error];
};
在這里,我們有了hook useCommentsRetriever。它以一個entityId作為參數。這將是我們文章的ID或博客文章的ID。然后,它類似于組件中的內容。不同之處在于此自定義hook需要返回某些內容。我選擇在這里返回一個數組。第一個元素是注釋,第二個元素是錯誤。
它將以這種方式使用:
//Import the custom hook
import useCommentsRetriever from './useCommentsRetriever.js'
const ArticleWithComments = (articleId) => {
const [comments, error] = useCommentsRetriever(articleId)
return (
// Do something in the DOM
)
}
const BlogPostWithComments = (blogPostId) => {
const [comments, error] = useCommentsRetriever(blogPostId)
return (
// Do something in the DOM
)
}
看看我們需要寫多少代碼?該useCommentsRetriever一個id作為參數。這[comments, error]
就是我們所謂的數組解構。hookuseCommentsRetriever返回一個數組。我們將該數組的第一項分配給變量名注釋,將該數組的第二項分配給變量名錯誤。
請注意,我可以根據需要使用任何方式命名這些變量。我在兩個部分中也可以使用不同的名稱。因此,當您看到useStatehook中使用的語法相同時,這是因為useState hook還返回了一個數組
我們是否必須開始使用自定義hook?
根據React文檔,是的。
您可以查看文檔中的hook規則以獲取更多信息。
自定義hook的隔離特性
如果在兩個組件中使用相同的自定義hook,則它們將不會共享狀態。BlogPostWithComments中的狀態將與ArticleWithComments中的狀態完全分開。每個自定義hook都會使用React中的useState和useEffect創建一個新函數。我們可以在同一個組件內使用多個hook,此處應用相同的邏輯。
總結
自定義hook可以讓您在編寫React代碼時真正發揮想象力。您可以采用類組件無法實現的方式提取和共享邏輯。