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,主要是調用 ChatAPIsubscribeToFriendStatus 函式來接收 friendIDhandleStatusChange,如果有拿到 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,當調用 useDocumentTitletitle 就會更新。

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 的基本使用都整理完了,實作上最常用到的還是 useStateuseEffectuseContextuseReducer 幾個方法。Hook 有著自己本身的渲染順序,讓我們在 function component 中也能達到生命週期的效果,而且使用上更為簡便,不難理解為何 function component 使用的頻率越來越高。


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

尚未有邦友留言

立即登入留言