當面試官問自定義Hook的時候他想知道什麼

希沃ENOW大前端javascript

公司官網:CVTE(廣州視源股份)css

團隊:CVTE旗下將來教育希沃軟件平臺中心enow團隊html

本文做者:前端

一兵名片.png

前言

在聽到這麼一個問題的時候,首先腦海中整體思路是這樣子的:java

  • 認識自定義Hook的基本概念
  • 可以使用自定義Hook進行復用邏輯的封裝
  • 瞭解自定義Hook的最佳實踐與工做原理
  • 進一步深刻Hook底層原理思想
  • 創造新的輪子思想,借鑑Reack Hook思想

什麼是React自定義Hook

HookReact 16.8 的新增特性。它可讓你在不編寫 class 的狀況下使用 state 以及其餘的 React 特性。React官方提供了經常使用的StateHookEffectHook分別用以管理函數式組件狀態和反作用。(React Hook官方介紹)react

除了官方提供的StateHook和EffectHook外,咱們能夠本身將經常使用的組件邏輯抽取到可重用的函數中,該函數須以React約定的形式來命名與使用,用以共享組件邏輯。git

那麼如何編寫咱們本身的自定義Hook

經過一個簡單的例子來看一下 好比咱們須要在拿到某個數據後設置頁面標題,並且須要在各個頁面裏面使用github

import React, { useState, useEffect } from 'react';

export default function App() { 
    // 正常咱們這樣子實現
    const [title, setTitle] = useState('默認標題')
    
    useEffect(() => {
        document.title = title;
    }, [title]);
    
    const onTitleChange = (event) => {
        setTitle(event.target.value);
    }
    
    return (<div> <h2>{title}</h2> <input type="text" onInput={onTitleChange}/> </div>)
}
複製代碼
  • 抽取共用邏輯,封裝成自定義Hook
export function useSetPageTitle (initTitle) {
  const [title, setTitle] = useState(initTitle || '默認標題');

  useEffect(() => {
    document.title = title;
  }, [title]);

  return [title, setTitle]
}
複製代碼
  • 在其餘組件中使用剛剛寫的useSetPageTitle
import { useSetPageTitle } from '../App';

export default function Chirld() { 
    // 這裏使用剛纔寫自定義Hook
    const [title, setTitle] = useSetPageTitle();
    
    return (<div> <h2>{title}</h2> <input type="text" onInput={onTitleChange}/> </div>>)
}
複製代碼

這樣子一個自定義的hook就成型了,是否是瞬間感受逼格提升了,原來我也能夠寫個這麼高大上的自定義Hook,哈哈哈。npm

聰明的大家必定發現了下面的特色數組

React約定自定義 Hook 必須以 use 開頭

上面的例子中使用【useSetPageTitle】。不遵循的話,因爲沒法判斷某個函數是否包含對其內部 Hook 的調用,React 將沒法自動檢查你的 Hook 是否違反了 Hook 的規則。

自定義Hook可自由搭配其餘hook使用

你能夠自由使用其餘內部Hook和其餘自定義Hook.上面演示例子中使用useStateuseEffect.

只在 React 的函數組件中最頂層使用 Hook

這樣作是爲了確保 Hook 在每一次渲染中都按照一樣的順序被調用。若是不是最頂層會致使狀態或者執行方法出錯進而致使BUG

  • 反例

state='A'條件知足時執行調用Hook順序是正常,當後續渲染條件不知足時,則React調用Hook順序出錯,則會致使方法和狀態邏輯執行出錯。

import React, { useState, useEffect } from 'react';
import './App.css';
import { useSetPageTitle } from './hooks';

export default function App() {
  const [state, setState] = useState('A');
  
  // 反例
  if (state === 'A') { 
      useEffect(() => {
        console.log('只執行一次')
      }, [state]);
  }
 
  useState({});

  useEffect(() => {
    // 獲取數據
  }, []);

  useState({});

  console.log(title)

  return (
    <div className="App"> <p> Hello React Hook! </p> </div>
  );
}
複製代碼
  • 正例
import React, { useState, useEffect } from 'react';

export default function App() {

  const [state, setState] = useState('A');
  
  useEffect(() => {
    if (state === 'A') { 
        console.log('執行相應的邏輯')
    }
   
  }, [state]);

  useState({});

  useEffect(() => {
    // 獲取數據
  }, []);

  useState({});



  return (
    <div className="App"> <p> Hello React Hook! </p> </div>
  );
}
複製代碼

爲了不出錯咱們可使用ESLint插件來檢測強制執行這些規則。 另外,親測React官方提供的create-react-app @3.x與@4.x在eject後已經集成了插件

eslint-plugin-react-hooks
複製代碼
// 你的 ESLint 配置
{
  "plugins": [
    // ...
    "react-hooks"
  ],
  "rules": {
    // ...
    "react-hooks/rules-of-hooks": "error", // 檢查 Hook 的規則
    "react-hooks/exhaustive-deps": "warn" // 檢查 effect 的依賴
  }
}
複製代碼

那麼咱們能夠在哪些場景識別抽取自定義hook呢?

自定義 Hook 解決了之前在React組件中沒法靈活共享邏輯的問題。那麼業務開發中可建立各類的自定義Hook,公共輔助函數、狀態複用、邏輯複用、效果複用、操做複用、生命週期模擬以及多種組合複用等只有想不到,相信很難有這麼聰明的大家作不到的場景實現。

下面舉幾個簡單栗子,拋磚引玉

  • 例如使用useMount模擬生命週期componentDidMount
import React, { useState, useEffect } from 'react';

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

export default function App() {

  useMount(() => {
     // 你的邏輯
  })


  return (
    <div className="App"> <p> Hello React Hook! </p> </div>
  );
}
複製代碼
  • 利用useEffect返回函數是銷燬才調用的機制來模擬unmount
function useUnmount (fn) {
    useEffect(() => {
        return () => {
            fn();
        }
    }, []);
}

export default function App() {

   useUnmount(() => {
        console.log('銷燬組件時輸出')
   })
 

  return (
    <div className="App"> <p> Hello React Hook! </p> </div>
  );
}
複製代碼
  • 監聽窗口變化
import React, { useState, useEffect } from 'react';

function useOnResize (fn) {
    useEffect(() => {
        window.addEventListener('resize',fn);
        return () => {
            window.removeEventListener('resize',fn)
        }
    }, []);
}

export default function App() {

   useOnResize(() => {
        console.log(document.body.clientWidth)
   })
 
  return (
    <div className="App"> <p> Hello React Hook! </p> </div>
  );
}
複製代碼

這裏介紹一些有趣的Hooks庫供使用與參考

由螞蟻 umi 團隊、淘系 ice 團隊以及阿里體育團隊共同建設的 React Hooks 工具庫ahooks

Set of a helpful hooks, for different specific to some primitives types state changing helpers.

可使建立彈窗,提示,菜單變得很是容易,提供了建立DOM層次以外的元素的功能

用於發起Http請求的優秀Hook

發現更多優秀Hook庫可在下面評論貼上,整一個優秀Hooks庫的集合

進階Hooks優秀實踐與工做原理

筆者並無實際看過React源碼,僅看過一些React Hook工做原理的文章。 這裏拋轉引玉,看過幾個比較好來分享。歡迎留言更多優秀實踐和原理剖析。

創造新輪子

迎(bu)接(yao)新(geng)輪(xin)子(le),向(biao)着(shi)新(xue)輪(bu)子(dong)前(le)進

參考資料

hooks-custom官方介紹

相關文章
相關標籤/搜索