天天看點

如何寫自定義 React Hook?

作者:前端西瓜哥

大家好,我是在學習 React 的前端西瓜哥。

我們在寫 React 函數元件時,如果想要複用元件的部分邏輯,可以考慮寫自定義 Hook。本文會教大家如何寫自定義 React Hook。

Hook 的規則

在此之前,我們先了解一下 Hook 的使用規則。

首先 Hook 隻能在函數元件的頂層使用,不能在循環、條件、嵌套函數中執行。

這和 React Hook 的實作原理有關。當第一次執行函數元件時,React 會配置設定一個對象,然後一個個調用 Hook 時,将傳入的參數或得到的結果依次放入到有序的表中緩存起來,然後儲存在該對象中。

之後再次執行函數元件時,必須要保證這些 Hook 的執行順序相同,才能做依賴項的對比,以及和前一次渲染的狀态的對比等對比邏輯。

如果能 hook 可以出現循環、條件、嵌套函數中,就不能保證 Hook 執行順序不變。

此外Hook 隻能在函數元件内工作,不要在非元件函數中使用 Hook。

如果你在普通函數内使用了 Hook,React 會報錯。

當然如果是自定義 Hook(一個使用了 React 内置 Hook 的普通函數),然後放到函數元件内,那也是合法的。

為防止開發者不小心寫岔,React 官方還寫了一個名為 eslint-plugin-react-hooks 的 ESLint 插件,用于檢測不合法的 Hook 調用位置,實在是太貼心了。強烈建議使用。

寫自定義 Hook

自定義 Hook,就是使用了内置 Hook 的普通函數。它是對函數元件可複用的部分邏輯的做了一層封裝,然後再被函數元件使用。

自定義的 Hook 必須使用 use 開頭。因為 React 的官方 ESLint 插件認為 use 開頭是自定義 Hook。

如果你不用 use 開頭,ESLint 插件就會認為這是一個普通函數,調用時不符合 Hook 規則時不會報錯,你就可能寫出有問題的代碼。

另外,自定義 Hook 下使用的 Hook,也必須位于頂層,這也是為了保證 hook 的順序多次執行能保持一緻。

下面我們來寫幾個常用的自定義 Hook。

useMount / useUnmount

我們希望實作類似類函數 componentDidMount 的效果。

const useMount = fn => {
  useEffect(() => {
    fn();
  }, []);
}
           

使用方式:

function App = () => {  
  // 自定義 Hook
  useEffect(() => {
    console.log('挂載');
  });
  
  // 原來的寫法
  useEffect(() => {
    console.log('挂載');
  }, []);
}
           

相比原來的 useEffect 的實作,做了封裝後的 useMount 更語義化一些。此外也不需要寫多餘的依賴項,并将元件銷毀的回調函數也隔離出去了。

類似類函數 componentWillUnmount 的 useUnmount Hook 實作如下:

const useUnmount = fn => {
  useEffect(() => fn, []);
}

// 用法
useUnmount(() => {
  console.log('銷毀');
})
           

useUpdateEffect

下面我們再實作一個 useEffect 的剔除掉挂載那一次的版本,對标類函數的 componentDidUpdate。

const useUpdateEffect = (fn, deps) => {
  const isMount = useRef(true);
  useEffect(() => {
    if (isMount.current) {
      isMount.current = false;
      return;
    }
    return fn();
  }, deps);
}

// 用法
useUpdateEffect(() => {
  console.log('更新');
})
           

思路其實很簡單,就是多使用一個預設值為 true 的布爾值變量。我們用它來記錄目前是否為第一次執行,如果是,就不執行傳入的函數,然後将布爾值設定為 false。

false 代表之後都是第二次第三次的執行,每次都執行傳入的函數。

這裡我們沒有用 useState,因為通過 setState 方法會重新渲染元件。是以我們使用了 useRef,修改它的值不會觸發元件的更新。

結尾

自定義 Hook,是一種比元件更小粒度的可複用邏輯組織方式,這也是 React 函數元件帶給我們最大的驚喜。為此,我們有必要學習好自定義 Hook。

我是前端西瓜哥,歡迎關注我。

繼續閱讀