深入理解 useState

useState

const [state, setState] = useState(initialState)

返回一個 state,以及更新 state 的函數。

在初始渲染期間,返回的狀態 (state) 與傳入的第一個參數 (initialState) 值相同。

initialState 參數只會在組件的初始渲染中起作用,後續渲染時會被忽略。如果初始 state 需要通過複雜計算獲得,則可以傳入一個函數,在函數中計算並返回初始的 state,此函數只在初始渲染時被調用:

const [state, setState] = useState(() => {
  const initialState = []
  for (let i = 0; i < 100; i++) {
    initialState.push(i)
  }
  return initialState
})

如果你更新 State Hook 後的 state 與當前的 state 相同時,React 將跳過子組件的渲染並且不會觸發 effect 的執行。(React 使用 Object.is 比較算法 來比較 state。)

function Child () {
  useEffect(() => {
    console.log('Child')
  })
  return <div>Child</div>
}
function App() {
  const [val, setVal] = useState(1)
  const handleClick = (e) => {
    setVal(1)
  }
  return (
    <div class>
      <div>{val}</div>
      <button onClick={handleClick}>點擊</button>
      <Child></Child>
    </div>
  );
}

某些場景下,useReducer 會比 useState 更適用,例如 state 邏輯較複雜且包含多個子值,或者下一個 state 依賴於之前的 state 等。並且,使用 useReducer 還能給那些會觸發深更新的組件做性能優化,因爲你可以向子組件傳遞 dispatch 而不是回調函數 。

function Child (props) {
  console.log('重新渲染')
  function handleClick () {
    props.dispatch({type: 'increment'})
  }
  return (
    <button onClick={handleClick}>按鈕</button>
  )
}
Child = React.memo(Child)
function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  function handleClick() {
    dispatch({type: 'increment'})
  }
  return (
    <div>
      <h1 onClick={handleClick}>{state.count}</h1>
      <Child dispatch={dispatch} />
    </div>
  )
}

React 會確保 dispatch 函數的標識是穩定的,並且不會在組件重新渲染時改變。這就是爲什麼可以安全地從 useEffect 或 useCallback 的依賴列表中省略 dispatch。

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  function handleClick() {
    dispatch({type: 'increment'})
  }
  const callback = useCallback(() => {
    dispatch({type: 'increment'})
  }, [])
  return (
    <div>
      <h1 onClick={handleClick}>{state.count}</h1>
      <Child callback={callback} />
    </div>
  )
}

如果直接從 useReducer 返回操作,則其行爲與 useState 幾乎相同。

function App() {
  const [name, setName] = useReducer((_, value) => value, '請輸入');
  return (
    <div class>
      <input value={name} onChange={e => setName(e.target.value)} />
    </div>
  );
}
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/ckxeUOTIBCdynVUAvPKF6w