useState
在 React 函數(shù)組件中存儲(chǔ)內(nèi)部 state 通常會(huì)使用 useState hook 傳入一個(gè)初始值,在初次渲染時(shí)創(chuàng)建 state,之后會(huì)返回當(dāng)前的 state。
const [state, setState] = useState(initialState)
下面是一個(gè)點(diǎn)擊+1的 demo
function App() {
const [n, setN] = useState(0);
return (
<div className="App">
<p>{n}</p>
<p>
<button onClick={() => setN(n + 1)}>+1</button>
</p>
</div>
)
}
- useState 接收一個(gè)初始值,返回一個(gè)length 為2 的數(shù)組;
- 數(shù)組第一項(xiàng)首次渲染時(shí)與初始值相等,第二項(xiàng)為一個(gè)函數(shù),接收一個(gè)新的值或者函數(shù),將新的值設(shè)置為新的 state
- useState 聲明在函數(shù)組件頂層,每次渲染都會(huì)執(zhí)行
知道原理之后,實(shí)現(xiàn)一個(gè)簡(jiǎn)易版的 useState
實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 useState
let state
const myUseState = (initialState) => {
state = state === undefined ? initialState : state
const setState = (newState) => {
state = newState
// 執(zhí)行渲染函數(shù)
}
return [state, setState]
}
這樣寫(xiě)組件只能初始化一個(gè)變量,如果有多個(gè)怎么辦?
let state = []
let index = 0 // 使用 index 來(lái)記錄組件內(nèi) useState 順序
const myUseState = (initialState) => {
let currentIndex = index
state[currentIndex ] = state[currentIndex ] === undefined ? initialState : state[currentIndex ]
const setState = (newState) => {
state[currentIndex ] = newState
index = 0 // 重置 index
// 執(zhí)行渲染函數(shù)
}
index++
return [state[currentIndex ], setState]
}
每次組件渲染,執(zhí)行 myUseState,如果沒(méi)有觸發(fā) setState 函數(shù),則會(huì)將初始值賦值給 state,執(zhí)行 setState 后組件會(huì)再此渲染一次,此時(shí) 產(chǎn)生一個(gè)新的 state,值為 newState,然后將這個(gè)新的 state 返回。所以,setState 并不會(huì)改變?cè)械?state,而是產(chǎn)生一個(gè)新的 state。
如果組件內(nèi)有多個(gè) useState
- 通過(guò) index 可以記錄 useState 的順序;
- 每次渲染都是產(chǎn)生新的 state[currentIndex]
- 每次渲染 useState 的順序不能發(fā)生改變,所以不能在條件語(yǔ)句中使用 useState
- setState 并不會(huì)改變?cè)械?state,而是產(chǎn)生一個(gè)新的 state.
useReducer
const [state, dispatch] = useReducer(reducer, initialArg, init);
useReducer 接收一個(gè)形如 (state, action) => newState 的 reducer,并返回當(dāng)前的 state 以及與其對(duì)應(yīng)的 dispatch 方法;
如果 state 邏輯較復(fù)雜且包含多個(gè)子值,或者下一個(gè) state 依賴(lài)于之前的 state 時(shí),useReducer 比 useState 更加適用。
const initialState = {n: 0}
const reducer = (state, action) => {
switch (action.type) {
case '+':
return {n: state.n + 1};
case '-':
return {n: state.n - 1};
default:
alert('unknow type')
break;
}
}
function App() {
const [state, dispatch] = useReducer(reducer, initialState)
return (
<div className="App">
<h1>n: {state.n}</h1>
<button onClick={() => dispatch({type: '+'})}>+1</button>
<button onClick={() => dispatch({type: '-'})}>-1</button>
</div>
);
}
使用 useReducer 步驟:
- 創(chuàng)建初始值:initialState ;
- 創(chuàng)建所有操作內(nèi)容:reducer;
- 傳入 useReducer 函數(shù)中,返回相應(yīng)的讀寫(xiě);
- 使用 dispatch 傳入對(duì)應(yīng)的 action 的 type 實(shí)現(xiàn)對(duì) state 的操作。