useState & useReducer

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 的操作。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容