React 筆記 - useState
在過去 (React 16.8之前), React 的 Function Components 無法進行 State 的管理,因為它僅具有接收 Props 以及回傳 JSX 的的功能,若要進行 State 的管理,勢必要使用到 Class Components ,然而 Class Components 通常會需要初始化 State 、加入生命週期 (如 componentDidMount , componentDidUpdate ...) 、定義 Event Handler 等等,因此程式碼容易變得過於複雜。
| Function Components | Class Components |
|---|---|
| 可回傳JSX內容 | 可回傳JSX內容 |
| 無法管理State | 可以管理State |
| 無法加入生命週期 | 可以加入生命週期 |
| 程式碼較輕量化 | 程式碼可能會較複雜 |
幸虧在 React 16.8 以後出現了 React Hooks ,讓我們能在 Function Component 內進行 State 以及生命週期的操作。 有了 React Hooks ,就可以避免編寫冗長複雜的 Class Components 。
React Hooks 只能使用在 Function Components。
使用 Hooks 時必須遵守的準則
-
React Hooks 僅限於使用在 Function Component 上。
-
在 Function Component 內的頂端 (Top Level) 就使用 React Hooks。
React Hooks 中的 useState
在 Function Components 中,我們可以過 React Hooks 所提供的 useState() 來定義我們的 State,在 useState() 的括號內部可以讓我們傳入 State 的預設值,該預設值可以是任何形式,如 Object、 Array 、 Number 、 String 、 Boolean 。
Class Components 的 State 必須是 Object ,但在 Function Component 的 State 可以是任何形式。
呼叫 useState() 之後會回傳一個陣列,如下方程式碼,陣列中的第一項 state 就是State當下的值,第二項 setState 是可以用來更新State的函式,其功能如同Class Component的 this.setState() 。
由於程式碼中
state以及setState的名稱是透過解構賦值 (Array destructuring) 得來的,其名稱可以自己任取。
如何更新State
useState() 回傳的陣列第二項是可以用來更新State的函式,如下方的 setState() ,其用法與 Class Components "類似",只要在函式的括號內傳入要更新的值即可
倘若更新過程需要存取前一次的 State ,如下方程式碼,在 setState() 的括號內可以接受一個匿名函式,其匿名函式的第一個參數即為前次的 State ,並在函式內回傳更新後的 State。
State Update : Function & Class 的差異
-
Class Component :
在 Class Components 當中,由於 State 的形式一直都是 Object ,在更新過程中, React 會自動將更新的值合併 (merge) 到 State 內部。如下方程式碼。 -
Function Component :
由於 State 在 React Hooks 中可以是任何形式 ( Object, String , Number ...),也因此在更新過程中,
useState不會自動將更新的值合併到 State 內部。若 State 為 Object ,在更新過程中,我們可以透過 JavaScript 中的展開運算子 ( Spread Operator )來實現物件的更新
useState 在使用上更彈性
由於 useState 中的 State 不再受限於 Object 形式,因此更新 State 時不會自動合併,但我們可以在同一個 Function Component 之中加入多個 useState() 用來儲存不同的值,如下方程式碼,透過多個 useState() 的呼叫來定義 nameState 、 ageState 、 heightState ,也因此我們可以僅更新單一特定的State來避免影響到其他的 State 。
State 更新與批量更新
當我們在 Class Component 透過 setState 或在 Function Component 透過 useState 進行 State 的更新時,都會觸發 React 安排 Component 進行重新渲染 (re-render)。
什麼是批量更新 (Batch Updating) ?
該機制主要在 Event Handler 內發生,如下方程式碼,當點擊 <button> 觸發 clickHandler 時,並執行 setName() 以及 setAge() 兩個 State 的更新, 但在 clickHandler 內的 name 並沒有在 setName() 之後馬上更新 ( name 仍為 'Andy' )。
為什麼 State 不會再 Event Handler 內立刻更新?
上面的程式碼中,我們可能會認為 name='Andy' 應該要在 setName('Rick') 之後馬上更新成 name='Rick',但事實上, 我們只能在 Component 重新渲染之後才可以存取新的 State。
Scheduling 機制
React 在處理 Event Handler 內的 State 更新時,假設有 N 次的 setState (或useState)在其內部, React 會將這些 setState 們 (或 useState) 在合適的時機點 (Scheduling) 進行批量更新 (Batch Updating) ,此時的 Component 只需要重新渲染 1 次即可,這樣的機制主要可以避免 Component 重新渲染 N 次的情況出現,也因此我們無法在 Event Handler 內部立刻觀察到 State 更新後的結果。