React Hooks 使用指南

Hook 是 React 16.8 開(kāi)始支持的新特性,旨在用函數(shù)式組件代替類式組件。本文記錄常用Hook用法及注意點(diǎn)

1、useState

返回一個(gè) state,以及更新 state 的函數(shù)。給函數(shù)式組件增加內(nèi)部狀態(tài),狀態(tài)一旦變化,組件會(huì)重新渲染

const [state, setState] = useState(initialState);
  • useState 可以接受單值或函數(shù),若是函數(shù),則以函數(shù)返回值作為初始state,且該函數(shù)僅在初始化時(shí)執(zhí)行一次,后期組件更新不再執(zhí)行
  • setState 可以接受單值或函數(shù),若是函數(shù),則函數(shù)第一個(gè)參數(shù)是上一個(gè)state值,返回值若與上一個(gè)state值一樣,則組件不重新渲染
  • 與類式組件的setState不同,函數(shù)組件的 setState 不會(huì)合并所有狀態(tài),不過(guò)可以這樣做到:
setState(prevState => {
  // 也可以使用 Object.assign
  return {...prevState, ...updatedValues};
});
  • 使用 Object.is方法判斷前后 state 是否相等

2、useReducer

const [state, dispatch] = useReducer(reducer, initialArg, init);

當(dāng)傳入第三個(gè)函數(shù)參數(shù),則state=init(initialArg);否則 state = initialArg

  • useReducer 是 useState 的替代方案
  • reducer: (state, action) => newState
const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

3、useEffect

接收一個(gè)包含命令式、且可能有副作用代碼的函數(shù)A和一個(gè)依賴數(shù)組B作為參數(shù)。函數(shù)A會(huì)在組件渲染到屏幕之后執(zhí)行。每次重新渲染組件時(shí),B中的值不變化,則函數(shù)A不會(huì)重新執(zhí)行

useEffect(()=>{
    // 副作用代碼,如訂閱、dom操作、定時(shí)器、獲取數(shù)據(jù)等
},[]);
  • 函數(shù)A可以返回一個(gè)函數(shù),用于清除副作用,如取消訂閱、定時(shí)器等操作
  • 如果組件多次渲染(通常如此),則在執(zhí)行下一個(gè) effect 之前,上一個(gè) effect 就已被清除
  • 函數(shù)A會(huì)在瀏覽器繪制后延遲執(zhí)行,但會(huì)保證在任何新的渲染前執(zhí)行。因此不應(yīng)在函數(shù)A中執(zhí)行阻塞瀏覽器更新屏幕的操作,不然用戶會(huì)感覺(jué)到視覺(jué)上的不一致

4、useLayoutEffect

函數(shù)簽名與 useEffect 相同,會(huì)在所有的 DOM 變更之后同步調(diào)用 effect??梢允褂盟鼇?lái)讀取 DOM 布局并同步觸發(fā)重渲染。在瀏覽器執(zhí)行繪制之前,useLayoutEffect 內(nèi)部的更新計(jì)劃將被同步刷新。

  • useEffect 是異步的,useLayoutEffect 是同步的

5、useCallback

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

useCallback 返回第一個(gè)函數(shù)A參數(shù)的記憶化版本,該函數(shù)A的引用只有在依賴數(shù)組的元素發(fā)生改變時(shí)才會(huì)改變。useCallback本身會(huì)在每次重新渲染時(shí)執(zhí)行

6、useMemo

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

返回一個(gè)記憶化的值V,該值只有在依賴數(shù)組的元素發(fā)生改變時(shí)才會(huì)改變。useCallback本身會(huì)在每次重新渲染時(shí)執(zhí)行。

  • useCallBack 用于記憶函數(shù),useMemo 用于記憶需要復(fù)雜計(jì)算而來(lái)的衍生值
  • useMemo 的第一個(gè)函數(shù)參數(shù)在初次渲染時(shí)也會(huì)執(zhí)行

7、useRef

useRef 返回一個(gè)可變的 ref 對(duì)象,其 .current 屬性被初始化為傳入的參數(shù)(initialValue)。

// const refContainer = useRef(initialValue);
function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` 指向已掛載到 DOM 上的文本輸入元素
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}
  • ref 對(duì)象的 current 屬性值是可變的,可保存任何值
  • ref 對(duì)象內(nèi)容發(fā)生變化時(shí),useRef 并不會(huì)通知你。變更 .current 屬性不會(huì)引發(fā)組件重新渲染。
  • 回調(diào) ref
function MeasureExample() {
  const [height, setHeight] = useState(0);

  const measuredRef = useCallback(node => {
    if (node !== null) {
      setHeight(node.getBoundingClientRect().height);
    }
  }, []);

  return (
    <>
      <h1 ref={measuredRef}>Hello, world</h1>
      <h2>The above header is {Math.round(height)}px tall</h2>
    </>
  );
}

8、自定義 Hook

import { useState, useEffect } from 'react';

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}
  • 用 useXXX 命名
  • 通常內(nèi)部調(diào)用 useState,useEffect 等內(nèi)置hook
  • 返回值隨意
?著作權(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)容

  • 在學(xué)會(huì)使用React Hooks之前,可以先看一下相關(guān)原理學(xué)習(xí)React Hooks 前言 在 React 的世界...
    DC_er閱讀 9,188評(píng)論 1 16
  • Hook 是 React 16.8 的新增特性。它可以讓你在不編寫(xiě) class 的情況下使用 state 以及其他...
    孤獨(dú)的小色狼閱讀 403評(píng)論 0 0
  • 什么是 Hooks 以往,React 組件都是通過(guò) class 的形式來(lái)編寫(xiě),只有無(wú)狀態(tài)組件才可以用函數(shù)來(lái)編寫(xiě)。H...
    Actoress閱讀 1,159評(píng)論 0 0
  • 前言 自react16.8發(fā)布了正式版hook用法以來(lái),我們公司組件的寫(xiě)法逐漸由class向函數(shù)式組件+hook的...
    大春春閱讀 4,244評(píng)論 3 7
  • Hook 是 React 16.8 的新增特性。它可以讓你在不編寫(xiě) class 的情況下使用 state 以及其他...
    Oldboyyyy閱讀 4,910評(píng)論 0 3

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