iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 28
0
自我挑戰組

React 30 天學習歷程系列 第 28 篇

【Day 28】React Hook(五): 自定義 Hook 及 使用 Hook 的一些規則

  • 分享至 

  • xImage
  •  

自訂義 Hook

自定義 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')
}

使用 Hook 的一些規則

  1. 盡量在頂層調用 Hook
    盡量不要在迴圈、判斷式或是嵌套函式裡面調用 Hook 的語法,因為 Hook 的語法大多有自己的渲染順序,如果任意調用,可能會導致元件渲染時候出問題。如下面的範例中,兩個 useState,雖然不會有錯誤,但是可能會打破 useState 的調用順序。
const FriendStatus = (props) => {
    const [count, setCount] = useState(0) // 盡量在頂層調用
    
    if (props.name) {
        const [userName, setUseName] = useState(props.name)
    }
    
    return <div>
        { userName }
    </div>
}
  1. 在 function component 中調用 Hook
    React Hook 只支持 function component,因此不能在 class component 中調用,未來官方計畫將 React Hook 拓展到 class component 中。

小結

到這一篇算是把 Hook 的基本使用都整理完了,實作上最常用到的還是 useState、useEffect、useContext 及 useReducer 幾個方法。Hook 有著自己本身的渲染順序,讓我們在 function component 中也能達到生命週期的效果,而且使用上更為簡便,不難理解為何 function component 使用的頻率越來越高。


上一篇
【Day 27】React Hook(四): 其他 React Hook 的語法
下一篇
【Day 29】適合和 React 搭配的第三方套件
系列文
React 30 天學習歷程 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言