前言 Function Component?Class Component?React Hooks?這些到底是什麼東西呢?所以這一篇我們就要來認識一下 React 中的寫法以及其差異。
Function Component 與 Class Component 現行 React 基本上有兩種寫法,分別是 Function Component 與 Class Component,或許你沒聽過 Function Component,但你一定知道 React Hooks,而 React Hooks 所指的就是 Function Component,Class Component 則是 React 早期寫法而已。
這邊稍微挪用一下前面章節的 Class Component 範例程式碼:
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 class App extends React.Component { constructor (props ) { super (props); this .state = { count : 0 , }; this .handleClick = this .handleClick .bind (this ); } sayHi ( ) { window .alert ('Hello Ray.' ); } handleClick ( ) { this .setState ((prevState ) => ({ count : prevState.count += 1 , })); } render ( ) { return ( <div > <button onClick ={this.handleClick} > Count is: { this.state.count } </button > <hr /> <button type ="button" onClick ={ this.sayHi }> 打招呼</button > </div > ); } }const app = ReactDOM .createRoot (document .getElementById ('app' )); app.render (<App /> );
Class Component 非常好辨別,就是使用 ES6 的 Class 語法來建立,而基本上 Component 的概念依照官方文件來講其實就是一個 function 而裡面包含了 React Element 而已。
那麼 Function Component 呢?Function Component 又是如何呢?這邊讓我們看一下將上方 Class Component 轉成 Function Component 之後的樣子吧!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function App ( ){ const [count, setCount] = React .useState (0 ); function sayHi ( ) { window .alert ('Hello Ray.' ); } function handleClick ( ) { setCount ((prevState ) => prevState += 1 ) } return ( <div > <button type ="button" onClick ={ handleClick }> Count is: { count } </button > <hr /> <button type ="button" onClick ={ sayHi }> 打招呼</button > </div > ) }const app = document .querySelector ('#app' );const root = ReactDOM .createRoot (app); root.render (<App /> );
透過這兩個範例程式碼我們可以看到 Function Component 比 Class Component 簡潔許多,甚至少了一些艱深的語法,例如 ES6 Class、extends、constructor 以及最可怕的 this。
光一個 this 就可以出各種 this 考題考倒一推人,如果可以的話,我也會選擇不要寫 this。
那麼前面也有提到 Function Component 其實就是 React Hooks,Reach Hooks 是 React 在 16.8 新增的功能,而它主打的就是你不用再寫 class 就可以直接使用 React 相關功能。
看到這邊如果你是一名 Vue 開發者,你應該會感覺起來跟 Vue 非常相似,因為 Vue 也是一樣提供了兩種寫法,分別是…
選項式 API (Options API):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const { createApp } = Vue ;const app = createApp ({ data ( ) { return { count : 0 , }; }, methods : { sayHi ( ) { window .alert ('Hello Ray.' ); }, }, }); app.mount ('#app' );
以及組合式 API(Composition API)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const { createApp, ref } = Vue ;const app = createApp ({ setup ( ) { const count = ref (0 ); const sayHi = ( ) => { window .alert ('Hello Ray.' ); }; return { count, sayHi } }, }); app.mount ('#app' );
其實你會發現 Composition API 與 React Hooks 有些地方非常相似,因此你也可以把 Composition API 叫做 Vue Hooks 呢。(笑)
而 Vue 作者也有說 Composition API 主要是受 React Hooks 的啟發,因此可以在 React 與 Vue 之間發現兩者的差異。
React Hooks 使用規則 接著讓我們聊一下使用 React Hook 有哪些使用規則與限制吧。
基本上 React Hooks 只有兩個重點限制,分別是
只能在函式頂層使用
只能用於 Function Component
只能在函式頂層使用 什麼是「只能在函式頂層使用 」呢?舉例下方這幾種寫法都是會出現錯誤的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function App ( ){ function sayHi ( ) { const [count, setCount] = React .useState (0 ); } if (true ) { const [count, setCount] = React .useState (0 ); } for (let i = 0 ; i < 5 ; i += 1 ) { const [count, setCount] = React .useState (0 ); } return ( <div > <button type ="button" onClick ={ sayHi }> 打招呼</button > </div > ) }
正確寫法就只能寫在函式最外層
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function App ( ){ const [count, setCount] = React .useState (0 ); function sayHi ( ) { window .alert ('Hello!' ) } return ( <div > <button type ="button" onClick ={ sayHi }> 打招呼</button > </div > ) }
只能用於 Function Component React Hooks 本身是基於 Function Component 所設計的,因此就只能在 Function Component 中使用,是不能在 Class Components 中使用的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class App extends React.Component { constructor (props ) { const [count, setCount] = React .useState (0 ); super (props); this .state = { count : 0 , }; } sayHi ( ) { window .alert ('Hello Ray.' ); } render ( ) { return ( <div > <button type ="button" onClick ={ this.sayHi }> 打招呼</button > </div > ); } }
其實也不用特別去記,因為如果你真的做這種事情的話,你也可以在 Console 看到以下提示訊息:
1 2 3 4 5 Uncaught Error: Invalid hook call . Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:1 . You might have mismatching versions of React and the renderer (such as React DOM)2 . You might be breaking the Rules of Hooks3 . You might have more than one copy of React in the same app See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
除此之外 React Hooks 與 Vue3 composition API 一樣都是向後兼容的,因此是可以一個專案內同時擁有 Class Component 跟 Function Component 寫法。
這時候你可能會延伸一個問題「那我該用 Class Component 開發還是 Function Component?還是兩者一起?」其實這個問題在官方文件就有提到,所以就直接擷取官方文件 的說明
當你準備好時,我們鼓勵開始使用 Hook 撰寫你新的 component。確保你團隊的成員們使用 Hook 並熟悉本文件。我們並不鼓勵你重寫現有的 class component 成 Hook,除非你已經計劃重寫它們(例如:修正 bug)。 你不可以在 class component 內使用 Hook,但你絕對可以在單個 tree 中將 class 和 function component 與 Hook 混合使用。無論是 class 或 function component,使用 Hook 是該 component 實作的細節。從長遠來看,我們期待 Hook 可以是大家撰寫 React component 的主要方式。
因此其實看得出來 React Hooks 必定會成為主流,畢竟官方比較期望你使用 React Hooks。
後記 本文將會同步更新到我的部落格
整理這些技術筆記真的很花時間,如果你願意 關閉 Adblock 支持我,我會把這份感謝轉換成更多「踩坑轉避坑」的內容給你!ヽ(・∀・)ノ
Advertisement