自定義 Hook 其實是用 JS 函式搭配 React Hook 封裝成一個有特定用途或是重複使用邏輯的函式,名稱要有 use
,這個函式內也可以用調 React 本身的 Hook。下面是官方文件的一個例子,封裝了一個 useFriendStatus
。
在調用 useFriendStatus
時,必須傳入一個 friendID
參數。我們在這個自訂義 Hook 中先使用 useState
設定 isOnline
來判斷使用者是否有上線。這邊官方使用第三方套件 ChatAPI
,主要是調用 ChatAPI
的 subscribeToFriendStatus
函式來接收 friendID
和 handleStatusChange
,如果有拿到 friendID
就進行訂閱,訂閱成功就能知道用戶時否在線,最後 return
一個新的 isOnline
狀態。另外,也使用了 useEffect
的特性在元件銷毀時去取消訂閱。
import { useState, useEffect } from 'react';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
// 訂閱
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
// 在元件銷毀時,取消訂閱
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}
實際使用的時候,我們只需在元件中調用 useFriendStatus
,並傳入 id
,就能取得一個返回值,判斷上線狀態。
const FriendStatus = (props) => {
const isOnline = useFriendStatus(props.friend.id)
if (isOnline === null) {
return 'Loading...'
}
return <div>
{ isOnline ? 'Online' : 'Offline'}
</div>
}
下面我們再做一個簡單的修改標題範例,我們製作一個 useDocumentTitle
Hook,當調用 useDocumentTitle
,title
就會更新。
const useDocumentTitle = (title) => {
document.title = title
}
const TestComponent = (props) => {
useDocumentTitle('This is New Title')
}
但是像上面這樣子,每次調用 useDocumentTitle
,不管 title
有沒有改變,一定都會重複渲染。因此我們加上 useEffect
,並將陣列值設為 title
,這樣只有在 title
改變時才會修改標題。這就是一個簡易自訂義 Hook。
const useDocumentTitle = (title) => {
useEffect(() => {
document.title = title
}, [title])
}
const TestComponent = (props) => {
useDocumentTitle('This is New Title')
}
useState
,雖然不會有錯誤,但是可能會打破 useState
的調用順序。const FriendStatus = (props) => {
const [count, setCount] = useState(0) // 盡量在頂層調用
if (props.name) {
const [userName, setUseName] = useState(props.name)
}
return <div>
{ userName }
</div>
}
到這一篇算是把 Hook 的基本使用都整理完了,實作上最常用到的還是 useState
、useEffect
、useContext
及 useReducer
幾個方法。Hook 有著自己本身的渲染順序,讓我們在 function component 中也能達到生命週期的效果,而且使用上更為簡便,不難理解為何 function component 使用的頻率越來越高。