Hooks與普通函數的區別
在這裏的Hooks
具體指的是自定義Hooks
,自定義的Hooks
與我們定義的普通函數類似,都可以封裝邏輯,以實現邏輯的複用。Hooks
實際上是一種特殊的函數,而由於Hooks
的特殊實現,他們之間也存在着一定的區別。
描述
在我開始學習React Hooks
的時候,我就比較疑惑這個問題。首先看一下官方文檔,在自定義Hooks
的部分說明了,構建自己的Hooks
可以讓您將組件邏輯提取到可重用的函數中。如果僅僅是這樣的話,那麼我們也完全可以使用普通的函數來實現邏輯的複用,而沒必要去使用Hooks
了。
當然在這裏還是得先明確一點定義: 自定義Hooks
就是很明確的定義了,其以use
開頭,內部可以調用其他的Hooks
;在這裏描述的的普通函數指的是我們平時寫的抽離公共邏輯的函數,而不是在我們定義的普通函數中去調用其他Hooks
這種方式。如果在普通函數中調用了其他Hooks
,那麼這個函數就不再是普通函數了,除了違反了Hooks
的命名規則以外,那就完全是一個Hooks
的定義了。
實際上,Coding
比較重要的兩個概念是邏輯與數據,文檔中提到的將組件邏輯提取到可重用的函數中,重要的是邏輯這兩個字,而在兩個組件中使用相同的自定義Hooks
是不會共享State
的。如果我們直接編寫一個普通的函數,那麼對於其數據是在所有調用者中共享的,因爲其只是一個模塊,當然前提是我們不會去new
出一個新對象來保存狀態,在這裏只討論最plain
的調用方式,因爲Hooks
也是直接以非常plain
的方式進行調用的。
那麼也就是說,如果我們使用Hooks
的話,實際上由於可以調用useState
、useRef
等Hooks
,從而獲取了對於這個Fiber
的訪問方法,那麼也就相當於我們可以將狀態或者說數據存放於當前節點當中,而不是類似於普通函數在全局中共享。當然如果需要全局共享狀態的話,狀態管理方案是更好的選擇,而不是全局變量。
示例
舉一個例子,對於數據請求,我們通常會封裝一個request
函數,假如我們需要對這個函數做一層緩存,那麼就會有邏輯與數據的複用,在邏輯方面我們抽離出的方法差距不大,而對於數據緩存複用方面在這裏通過普通函數與自定義Hooks
的實現便是不同的。
普通函數
在普通函數當中,其就是一個模塊,因此其數據是在所有調用者中共享的,因此我們可以通過一個Map
來存儲數據,這樣就可以實現數據的複用。在這裏需要注意的是,如果我們的url
需要實現在不同組件調用返回的數據不同的話,例如可能會有根據當前頁面的referer
請求頭來決定返回數據的需求,那麼這種全局共享的數據就不適用了,就需要多添加一個參數來區分不同的數據,這樣就會導致邏輯與數據的耦合,因此這種方式不是很好。當然這也是基於特定需求的,在這裏只是舉一個例子,畢竟實際上適合的纔是最好的。
const cache = new Map();
export fetch = (url) => {
if (cache.has(url)) {
return cache.get(url);
}
const promise = fetch(url);
cache.set(url, promise);
return promise;
}
自定義Hooks
在自定義Hooks
當中,數據被鎖定在了Fiber
當中,也就是說數據的共享範圍是在當前組件節點中,相對於全局狀態共享來說粒度會更細一些。當然我們如果想直接在全局共享數據的話,這種方案就不合適了,可能還需要配合一個全局的狀態管理纔行。還是那句話,在這裏只是舉一個例子,畢竟實際上適合的纔是最好的。
const useRequest = (url) => {
const map = useRef(new Map());
if (map.current.has(url)) {
return map.current.get(url);
}
const promise = fetch(url);
map.current.set(url, promise);
return promise;
}
總結
簡單總結一下兩者的區別:
- 官方提供的
Hooks
只應該在React
函數組件/自定義Hooks
內調用,而不應該在普通函數調用。 - 自定義
Hooks
能夠調用諸如useState
、useRef
等,普通函數則不能。由此可以通過內置的Hooks
獲得Fiber
的訪問方式,可以實現在組件級別存儲數據的方案等。 - 自定義
Hooks
需要以use
開頭,普通函數則沒有這個限制。使用use
開頭並不是一個語法或者一個強制性的方案,更像是一個約定,就像是GET
請求約定語義不攜帶Body
一樣,使用use
開頭的目的就是讓React
識別出來這是個Hooks
,從而檢查這些規則約束,通常也會使用ESlint
配合eslint-plugin-react-hooks
檢查這些規則,從而提前避免錯誤的使用。
每日一題
https://github.com/WindrunnerMax/EveryDay
參考
https://www.zhihu.com/question/491311403
https://zh-hans.reactjs.org/docs/hooks-custom.html
https://stackoverflow.com/questions/60133412/react-custom-hooks-vs-normal-functions-what-is-the-difference