探索React Hooks:原來它們是這樣誕生的!

前端小智發表於2023-05-15
本文首發於微信公眾號:大遷世界, 我的微信:qq449245884,我會第一時間和你分享前端行業趨勢,學習途徑等等。
更多開源作品請看 GitHub https://github.com/qq449245884/xiaozhi ,包含一線大廠面試完整考點、資料以及我的系列文章。

快來免費體驗ChatGpt plus版本的,我們出的錢
體驗地址:https://chat.waixingyun.cn
可以加入網站底部技術群,一起找bug.

這篇文章《Where Did Hooks Come From?》主要討論了 React Hooks 的來源和背景。在引入 Hooks 之前,React 類需要擴充套件 React.Component 或 React.PureComponent,而 React 本身沒有提供共享程式碼的 API。因此,React 社群開發人員建立了兩種有效共享元件程式碼的模式,分別是高階元件(Higher Order Components,簡稱 HOC)和 Render Props。這些模式在一定程度上解決了程式碼重用的問題,但仍然存在一些侷限性。為了更好地解決這些問題,React Hooks 被引入,為開發者提供了一種更簡潔、易於理解的方式來共享和重用元件的邏輯。

下面是正文~~

Hooks 是用於在元件之間共享通用邏輯的。明確地說,我們所說的“邏輯”並不是指元件的 UI 部分(JSX)。我們談論的是元件中 JSX 之前的所有內容。在基於類的元件中,我們會說它在生命週期方法和自定義方法中。在功能元件中,它只是 JSX 之上的東西。

在某種程度上,Hooks 的故事與 React 及其先前用於共享程式碼的 API 的故事密切相關。所以請耐心聽我從頭說起...

2013:第一個React API:

React 開發者不喜歡 mixins,這是共享邏輯的第一個 API。

最初,React 有一種在元件之間共享通用邏輯的方法,稱為 mixins。這是在 JavaScript 擁有類之前的 React 早期。這些偽類看起來的元件允許“混入”可共享的邏輯。當時,mixins 被指責為社群開始流行的一些反模式的根本原因。因此,當 React 在 2016 年獲得真正的類時,大多數 React 開發人員為 mixins 的 API 消失而歡呼。

2016:類元件

在JavaScript在ES2015(ES6)中獲得類之後,React很快跟進了今天仍然可以使用的類元件。但是,如果你對React較為陌生,可能會想知道為什麼普遍認為應該在React中完全避免使用類元件?

主要原因是共享邏輯困難。當我們失去了 mixins 時,我們也失去了一種原始的共享程式碼方式。我們可以透過建立一個新元件來共享/重用 UI,以共享 JSX,但是沒有內建方法可以共享生命週期方法,例如 componentDidMountcomponentDidUpdatecomponentWillUnmount
這些特定方法是我們可能希望管理元件副作用的地方。因此,如果您用某個副作用編寫 ComponentOne ,我們將不得不將該邏輯複製到 ComponentTwo ,從而使邏輯無法以一種只編寫一次的方式抽象。

我們不能用繼承嗎?

class ComponentOne extends SharableStuff {
  // ...
}

class ComponentTwo extends SharableStuff {
  // ...
}

不,React 不允許我們編寫從其他元件繼承的元件。而且,即使 React 允許你這樣做,你將如何將多個邏輯體共享到 ComponentOne ?不允許多重繼承,所以這不起作用:

class ComponentOne extends SharableStuffA extends SharableStuffB {
  // ...
}

React類必須擴充套件 React.ComponentReact.PureComponent ,並且React本身沒有共享程式碼的API。

社群雖然很聰明。React 開發人員建立了兩種模式,有效地在元件之間共享程式碼,這兩種模式被稱為高階元件(Hoc)和 Render Props

無狀態函式元件

在同一時期,React 團隊宣佈了一種使用函式而不是類來建立元件的新方法。當時的主要想法是擁有一個僅接受屬性並可以返回 JSX 的元件。沒有狀態或使用類似於類生命週期方法的 React API 的能力。

我們稱之為無狀態函式元件,因為它們也不能有狀態。

不久之後,React 團隊告訴我們不要這樣稱呼它們。我們應該稱之為函式元件,因為...他們有計劃?

2018 Hooks

從本質上講,Hooks 只是我們可以從函式元件中呼叫的函式。我們可以使用內建的鉤子並編寫自己的:

  • 內建鉤子:這些API(如 useState() )使功能元件能夠“掛鉤”到React的所有功能。
  • 自定義鉤子:這些只是我們編寫的實現內建鉤子的函式。自定義鉤子的一般概念是為任何想要使用它的元件建立可重用的邏輯。

React 有 useState() ,因此函式元件可以擁有與類狀態類似的自己的本地狀態。但是,如果重新整理頁面,所有本地狀態都會重置(就像任何其他 JS 變數一樣)。因此,我們可以建立自己的 useLocalStorageState() ,它可能的工作方式與 useState() 完全相同,但還將狀態保持到 localStorage ,以便在重新整理後恢復值。

下面是一個使用自定義鉤子共享資料獲取邏輯的示例。你不必完全瞭解如何使用 useStateuseEffect ,只需要瞭解它們為元件執行一些邏輯,我想共享它。如果另一個元件也想根據 productId 獲取產品,那麼需要重新編寫下面高亮的程式碼:

image.png

這裡是相同的邏輯移至自定義鉤子。現在任何元件都可以使用 useFetchProduct 鉤子:

// Custom Hook
function useFetchProduct(productId) {
  const [product, setProduct] = useState(null)

  useEffect(() => {
    fetchProduct(productId).then((product) => setProduct(product))
  }, [productId])

  return product
}

function BrowseProducts({ productId }) {
  const product = useFetchProduct(productId)
  // return <div>...</div>
}

這是一個過於簡化的例子,上面的 useEffect 程式碼是不完整的。如果你想要一個獲取資料的自定義 Hook,推薦來自 React Query 的自定義鉤子,名為 useQuery()

如今,如果你願意,你仍然可以使用類。如果你覺得它們更容易使用,那完全取決於你。然而,在類之間共享邏輯時,你將會遇到問題。即使你可以接受這些問題,並且你不覺得高階元件(HOC)和 Render Props 混亂,與過去五年開始學習 React 的其他開發者合作或者組隊工作時,你可能會發現困難。

他們在 Hooks 被當作 React 主要方法教授時開始接觸 React。他們可能不瞭解類元件的“進退維谷”,如何處理這種奇怪的作用域問題,以及何時以及如何使用 HOC 或 Render Props。此外,React 生態系統中絕大多數第三方庫已經放棄了 HOC 和 Render Props,轉而採用了 Hooks。因此,你將無法輕鬆地使用它們的工具,因為 Hooks 僅適用於函式式元件。

我的一些朋友已經使用 React 很長時間了,他們記得這些討論和權衡。但是我注意到(至少在 Twitter 上),歷史正在重演。有一整代新的 React 開發者不知道這個背景故事,也不知道我們為什麼要有 Hooks。我承認,Hooks 的某些部分比類更難,比如我們可能需要記憶化( useMemouseCallback ),但這是一種權衡。你可以選擇使用帶有 HoC 和 Render Props 的類(也不容易),或者使用具有輕鬆共享程式碼能力的 Hooks,但需要理解記憶化的複雜性。

程式碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug

交流

有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

相關文章