Hooks與普通函數的區別

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的話,實際上由於可以調用useStateuseRefHooks,從而獲取了對於這個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能夠調用諸如useStateuseRef等,普通函數則不能。由此可以通過內置的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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章