Hooks 是 React 16 中的特性,解決函數組件想使用類組件的一些特性。
關於更多 Hooks 介紹,請參考 React 官網[1]
useState
之前是在類組件中使用狀態通過 state 定義,大概代碼是這樣的。
import React from 'react'; class Counter extends React.Component { state = { number: 0 } handleClick = () => { this.setState({ number: this.state.number + 1 }) } render() { return ( <> <p>{this.state.number}</p> <button onClick={ this.handleClick }> 改數字 </button> </> ); } } function render() { ReactDOM.render(<Counter />, document.getElementById('root')); } render()
但是函數組件沒有實例,也沒有狀態。函數組件使用狀態需要使用 useState 鈎子。
關於 useState 的用法是,需要傳入一個參數作為狀態的初始值,當函數執行后會返回兩個值,一個是當前狀態的屬性,一個是修改狀態的方法。
我們通過一個計數器的例子,當點擊按鈕表示狀態加1。
import React, {useState} from 'react'; function Counter() { const [ number, setNumber ] = useState(0) return ( <> <p>{number}</p> <button onClick={ () => setNumber(number + 1) } > 改數字 </button> </> ) } function render() { ReactDOM.render(<Counter />, document.getElementById('root')); } render()
現在我們已經掌握了它的用法,那么我們開始分析它的原理。
原理
我們需要寫一個 useState 方法,會返回當前狀態的屬性和設置狀態的方法,每當狀態改變之后,方法中會調用刷新視圖的 render 方法。
let memoizedState; function useState (initialState) { memoizedState = memoizedState || initialState function setState (newState) { memoizedState = newState render() } return [memoizedState, setState] }
再次嘗試之前的代碼,依然可以正常使用,但是當多個 useState 存在的時候就有問題了,只能變一個狀態了。
function Counter() { const [ number, setNumber ] = useState(0) const [ title, setTitle ] = useState('隨機標題') return ( <> <h1>{title}</h1> <p>{number}</p> <button onClick={ () => setNumber(number + 1) } > 改數字 </button> <button onClick={ () => setTitle(`隨機標題${Math.random()}`) } > 改標題 </button> </> ) }
現在我們需要優化我們的 Hooks ,解決多個 useState 同時使用的問題,當多個狀態存在的時候,我們需要使用數組保存狀態。
let memoizedStates = [] let index = 0 function useState (initialState) { memoizedStates[index] = memoizedStates[index] || initialState let currentIndex = index function setState (newState) { memoizedStates[currentIndex] = newState render() } return [memoizedStates[index++], setState] } function Counter() { const [ number, setNumber ] = useState(0) const [ title, setTitle ] = useState('隨機標題') return ( <> <h1>{title}</h1> <p>{number}</p> <button onClick={ () => setNumber(number + 1) } > 改數字 </button> <button onClick={ () => setTitle(`隨機標題${Math.random()}`) } > 改標題 </button> </> ) } function render() { index = 0 ReactDOM.render(<Counter />, document.getElementById('root')); } render()
現在已經完成了 useState 的基本原理,當你了解原理之后,使用 Hooks 就變得更加容易了。