終究都要學 React 何不現在學呢? - React 進階 - Custom Hook - (17)

前言

我們在前面章節認識到了許多 React Hooks,但是這些 Hooks 都是由 React 官方所提供的,那如果我們想自訂自己的 Hooks 可不可以?所以這一篇就要來認識 React Hook 中的 Custom Hook。

Custom Hook

那麼什麼是 Custom Hook?再提 Custom Hook 之前我們先提提另一件事情。

實際開發的時候往往會遇到重複性的邏輯,那麼當遇到重複性的邏輯時我們就會將這一段重複性的邏輯抽出來變成一個函式,以便我們重複的使用以及維護。

那麼為什麼要提到這件事情呢?因為 React 的 Custom Hook 就是在幫我們做這件事情,這時候你應該會有一個疑問點「Custom Hook 到底是什麼東西?」

其實就只是一個 JavaScript Function 而已,只是裡面有使用到 React Hook,就是這麼簡單。

那麼在使用 Custom Hook 時需要遵守一個基本的規則,也就是函式的名稱 (Function Name) 必須為 「use」 開頭,並且通常後方的函式名稱會是首字大寫,如同前面章節所認識到的其他 Hook 一樣

  • useState
  • useEffect
  • useCallback
  • useReducer
  • useMemo
  • useRef

你可以看到前面舉例的 React Hook 通通都是 use + 首字大寫名稱,那麼我們在撰寫 Custom Hook 的時候也是要遵守這個規則。

那麼接下來會舉例一些 Custom Hook 的簡單應用,這樣子可以讓你更加的了解 Custom Hook 的撰寫與應用。

useKeyDown

那麼第一個 Custom Hook 範例就讓我們來實作一個 useKeyDown 的 Custom Hook 吧!

首先目前底下程式碼是當你按下鍵盤上任一按鍵時,將會在畫面上顯示出你按下的按鍵

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const App = () => {
const [keyDown, setKeyDown] = React.useState('');

React.useEffect(() => {
document.addEventListener('keydown', (event) => {
setKeyDown(event.key);
});
return () => {
document.removeEventListener('keydown', ()=> {
setKeyDown('');
});
}
}, []);
return (
<div>
<h1>你目前按下的按鈕是:{ keyDown }</h1>
</div>
)
}

const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(<App />);

當我們在畫面上按下鍵盤時,可以看到畫面會不停的出現相對應的字母,如當你按下 a 按鈕畫面上就會出現 a 以此類推的效果。

那麼假使這一段 keydown 行為會被一直被重複使用,因此我們要將它抽出來,以便我們可以重複使用,請記住 Custom Hook 開頭請務必是 use,所以這邊命名一個函式叫做 useKeyDown

1
2
3
const useKeyDown = () => {
// ...
}

接著呢?接著將原本的 keydown 相關程式碼移至 useKeyDown 中,並且將 setKeyDown 的部分改為回傳出去,這樣子我們就可以在外部使用 useKeyDown 這個 Custom Hook,因此程式碼就會改成這樣

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const useKeyDown = () => {
const [keyDown, setKeyDown] = React.useState('');

React.useEffect(() => {
document.addEventListener('keydown', (event) => {
setKeyDown(event.key);
});
return () => {
document.removeEventListener('keydown', ()=> {
setKeyDown('');
});
}
}, []);

return keyDown;
}

接著要如何使用呢?其實很簡單,只要在你要使用的地方呼叫 useKeyDown 這個函式就可以了,如下面的程式碼所示

1
2
3
4
5
6
7
8
const App = () => {
const keyDown = useKeyDown();
return (
<div>
<h1>你目前按下的按鈕是:{ keyDown }</h1>
</div>
)
}

透過 Custom Hook 的方式,我們就可以將重複性的程式碼抽出來並重複使用,而這樣子我們的整體程式碼也可以更簡潔。

useLog

接著讓我們看另一個簡單的範例,當我們在 input 輸入任何文字時,就會觸發 console.log

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const App = () => {
const [ text, setText ] = React.useState('');
React.useEffect(() => {
console.log(text);
}, [text]);
return (
<div>
input: <input className="border" type="text" onChange={ (e) => setText(e.target.value) } />
<h1>你現在輸入的文字是:{ text }</h1>
</div>
)
}

const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(<App />);

上方範例程式碼非常簡單,我們可以看到每次只要在 input 輸入任何文字都會觸發放在 React.useEffect 中的 console.log,那麼這個技巧就有可能在許多地方使用,所以就可以封裝起來讓我們可以重複使用,所以首先先宣告一個函式叫做 useLog

1
2
3
const useLog = () => {
// ...
}

接著我們只要將原本的 console.log 放到 useLog 中,並且將 text 這個參數傳進去,這樣子我們就可以在外部使用 useLog 這個 Custom Hook,而剛好這一段程式碼是可以很簡潔的使用箭頭函式縮寫,所以就會變成以下

1
const useLog = (value) => React.useEffect(() => console.log(value), [value]);

接下來非常簡單,將要輸出的值傳入 useLog 即可,這樣就可以持續監聽特定 state 結果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const useLog = (value) => React.useEffect(() => console.log(value), [value]);

const App = () => {
const [ text, setText ] = React.useState('');
useLog(text);
return (
<div>
input: <input type="text" className="border" onChange={ (e) => setText(e.target.value) } />
<h1>你現在輸入的文字是:{ text }</h1>
</div>
)
}

const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(<App />);

透過上面兩個簡單的範例,我們可以看到 Custom Hook 可以很方便的製作出屬於我們自己的 Hook,除此之外每一個 Custom Hook 都有自己的 state,因此並不用擔心影響到其他的 state。

當然這邊只是舉例了一些簡單的 Custom Hook,如果你想看更多這類 Custom Hook 的範例的話,你可以參考「useHooks」與「React UseHook」這些網站,上面有許多不同的 Custom Hook 可以參考。

那麼接下來提醒一下從這一篇章節將會大幅減少 Vue 的比較範例而比較著重於 React 上,否則真的會有一種寫不完的感覺 QQ…

後記

本文將會同步更新到我的部落格