建立 hook 函式 自訂 hook 的第一步是建立 hook 函式,下面是追蹤滑鼠座標的一個 hook,函式會將值回傳出來
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const useMousePosition = ( ) => { const [mouse, setMouse] = useState ({}); useEffect (() => { const getMouseEvent = (e ) => { setMouse ({ x : e.clientX , y : e.clientY , }) } window .addEventListener ('mousemove' , getMouseEvent); return () => window .removeEventListener ('mousemove' , getMouseEvent) }, []); return mouse; }
元件內引入 hook 1 2 3 4 5 6 7 8 9 10 11 const App = ( ) => { const [text, setText] = useState ('' ); const mouse = useMousePosition (); return (<> { mouse.x} { mouse.y } <input type ="text" onChange ={e => { setText(e.target.value) }} /> </> )}
在元件內即可使用自訂 hook
自訂 hook 命名 自訂 hook 必須以 use 開頭命名,但如果 function 裡面沒有用到 hook 的話,不用 use開頭
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function useSorted (items ) { return items.slice ().sort (); } function getSorted (items ) { return items.slice ().sort (); } function useAuth ( ) { return useContext (Auth ); }
useAxios hook 前端專案常需要打 api 取回遠端資料,我們可以將發出網路請求的過程包成一個 custom hook 方便重複使用。這邊會以axios套件為範例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import { useState, useEffect } from 'react' ;import axios from 'axios' ;axios.defaults .baseURL = 'https://jsonplaceholder.typicode.com' ; export const useAxios = (axiosParams ) => { const [response, setResponse] = useState (undefined ); const [error, setError] = useState ('' ); const [loading, setloading] = useState (true ); const fetchData = async (params ) => { try { const result = await axios.request (params); setResponse (result.data ); } catch ( error ) { setError (error); } finally { setLoading (false ); } }; useEffect (() => { fetchData (axiosParams); }, []); return { response, error, loading }; };
useAxiosHook 將取的遠端資料的邏輯包裝在 useAxios.jsx 元件中,並將取得資料後的狀態 return 出來 response, error, loading;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import { useAxios } from 'axioshook' ;const App = ( ) => { const { response, loading, error } = useAxios ({ method : 'POST' , url : '/posts' , headers : { accept : '*/*' }, data : { userId : 1 , id : 19392 , title : 'title' , body : 'Sample text' , }, }); return ( <div className ='App' > <h1 > Posts</h1 > {loading ? ( <p > loading...</p > ) : ( <div > {error && ( <div > <p > {error.message}</p > </div > )} <div > { // no need to use another state to store data, response is sufficient response && <p > {response.id}</p > } </div > </div > )} </div > ); };
useToggle 專案中也常用到要切換 true 和 false 的情形,可以把切換的邏輯包成 hook
1 2 3 4 5 6 7 8 9 10 11 12 import { useState } from "react" ;export default function useToggle (defaultValue ) { const [value, setValue] = useState (defaultValue); function toggleValue (value ) { setValue (currentValue => { return typeof value === 'boolean' ? value : !currentValue; }) } return [value, toggleValue]; }
在元件中使用,當 toggleValue 沒有傳入參數時,就切換 value,有傳入 true 或 false,就套用 true或 false。
1 2 3 4 5 6 7 8 9 10 11 12 13 import useToggle from "./useToggle" ;export default function ToggleComponent ( ) { const [value, toggleValue] = useToggle (false ); return ( <div > <div > {value.toString()}</div > <button onClick ={toggleValue} > Toggle</button > <button onClick ={() => toggleValue(true)}>Make true</button > <button onClick ={() => toggleValue(false)}>Make false</button > </div > ) }
react 中表單操作的邏輯也可以包成 hook
1 2 3 4 5 6 7 8 9 10 11 12 export function useFormInput (initialValue ) { const [value, setValue] = useState (initialValue); function handleChange (e ) { setValue (e.target .value ); } const inputProps = { value : value, onChange : handleChange }; return inputProps; }
實際使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 export default function Form ( ) { const firstNameProps = useFormInput ('Mary' ); const lastNameProps = useFormInput ('Poppins' ); return ( <> <label > First name: <input {...firstNameProps } /> </label > <label > Last name: <input {...lastNameProps } /> </label > <p > <b > Good morning, {firstNameProps.value} {lastNameProps.value}.</b > </p > </> ); }
useTimeout useTimeoutHook
這段代碼是一個自定義的 React Hook,稱為 useTimeout。它用來處理延遲執行的功能,並提供設置(set)、清除(clear)和重置(reset)計時器的能力。以下是代碼的邏輯分解:
參數與變數初始化:
useTimeout(callback, delay) 接收兩個參數:
callback:當計時器到達 delay 時要執行的函數。
delay:設定延遲時間(毫秒)。
callbackRef 和 timeoutRef 是兩個 useRef 引用,用於保存 callback 函數和計時器的 ID,確保它們在 Hook 中保持一致。
設定計時器 (set):
set 是一個透過 useCallback 儲存的函數,用來設置計時器。
當 set 被調用時,它會根據 delay 使用 setTimeout 來執行 callbackRef.current()。
[delay] 為依賴項,當 delay 改變時重新生成 set。
清除計時器 (clear):
clear 也是用 useCallback 儲存的函數,用來清除計時器。
它檢查 timeoutRef.current 是否存在,如果存在則使用 clearTimeout 來清除計時器。
自動執行 set 和清除計時器:
在第二個 useEffect 中,執行 set 來啟動計時器,並返回 clear 作為清理函數,確保當 delay、set 或 clear 改變時可以自動清除計時器並重新設置。
[delay, set, clear] 為依賴項,當這些值變化時會重新執行 useEffect。
重置計時器 (reset):
reset 是一個 useCallback 儲存的函數,先清除計時器,再重新設置計時器。
[clear, set] 為依賴項,當 clear 或 set 改變時,重置函數也會重新生成。
回傳 reset 和 clear:
最後,useTimeout 回傳 reset 和 clear 函數,以便在使用這個 Hook 的組件中可以調用這兩個函數來手動控制計時器。