react 進階必學 hook (四):自定義hook

系列文章傳送門:

react 進階必學 hook (一):useState 來一碗大碗寬面

react 進階必學 hook (二):useEffect 專治不吃寬面

react 進階必學 hook (三):useContext 麪館分店開張了

react 進階必學 hook (四):自定義hook

什麼是自定義hook

官網原話如下:

自定義 Hook 是一個函數,其名稱以 “use” 開頭,函數內部可以調用其他的 Hook,自定義 Hook 是一種自然遵循 Hook 設計的約定,而並不是 React 的特性

自定義hook有一下特性或是約定:

在這裏插入圖片描述

  • 自定義hook中可以調用其他hook
  • 必須以use開頭,就像組件必須以大寫字母開頭一樣
  • 自定義hook中管理state也是使用useState、useEffect,因爲useState在調用的時候就是完全獨立的

自定義hook解決了什麼問題

想必開發人員對utils文件夾都很熟悉,在開發的時候我們會把經常使用的一些方法函數放到utils文件夾中,因爲這些邏輯方法的複用率很高;同樣自定義hook也是解決類似的問題。

React的組件思想其實就是一種將代碼複用的做法,然而在編寫組件的過程中又有一些邏輯是可以複用的,但是這些邏輯不需要在ui上展示或是有些組件不能在更細的拆分,因此我們可以將這些邏輯抽象成自定義hook,和組件的抽象不是一個緯度,就像抽象工廠模式;這種功能的抽象,嚴格控制輸入輸出,還有點函數式編程的思想,自定義的hook我們可以在不同的組件中使用,就像utils中的方法一樣。

麪館例子

react 進階必學 hook (三):useContext 麪館分店開張了中我們添加了一個統計一共賣出多少面的需求,每一個麪館賣出一碗麪後都做了兩個動作:

  1. 自己麪館的counter顯式加一
  2. 麪館總計的counter顯式加一

代碼如下:

    const [count, setCount] = useState(0); 
    const {counter, add} = useContext(context)

    useEffect(() => {            
        add()
        return window.alert(`一共賣出${counter}碗💪💪💪💪`)
    }, [count])

其中 const [count, setCount] = useState(0);是本麪館的counter,add()控制的是上下文中的總計的counter,兩個是分開的,但是仔細想一下,這兩個過程其實是嚴格綁定的,如果添加其他面的品類,添加新的邏輯就會分散導致不好維護,因此可以將這個邏輯寫成一個hook。

1. 創建自定義hook

我們先創建一個自定義hook,命名爲useCounter,因爲要求必須以use開頭:

export default function useCounter(initialState) {
    const [count, setCount] = useState(initialState)
    const {counter, add} = useContext(context)
    
    const setCounter = ()=>{
        setCount(count+1)  // 本麪館狀態更改
        add()  // 總計更改
    }

    useEffect(() => {
        window.alert(`一共賣出${counter}碗💪💪💪💪`)
    }, [count])

    return [count, setCounter]
}

對於自定義hook的返回return [count, setCounter]中使用[]還是{},要分情況處理,使用時需要更換變量名的話建議用[]

2. 修改麪館邏輯,使用自定義hook

想useState一樣使用即可:

const [count, setCount] = useCounter(0);

完整代碼如下:

import React, {useState} from 'react';
import useCounter from './useCounter'

export default function Counter(props) {

    const [count, setCount] = useCounter(0);  // 使用自定義hook
    const [big, setSize] = useState(true);
    const [type, setType] = useState("寬面");
    const size = (big)=>big? "大":"小";

    return (
        <div>
            <h3>麪館{props.shop}</h3>
            <h2>老闆,來{count}{size(big)}{type}</h2>
            <button onClick={()=> setCount(count+1)} style={{"height":"40px"}}>加一碗</button>
            <button onClick={()=> setSize(!big)} style={{"height":"40px"}}>{size(!big)}</button>
            <button onClick={()=> setType("細面")} style={{"height":"40px"}}>不想吃寬面</button>
        </div>
    );
}

對比一下之前的代碼,其實組件內部也乾淨了不少:

![Peek 2020-05-31 19-29](/home/ffzs/視頻/Peek 2020-05-31 19-29.gifexport default function Counter(props) {
    const [count, setCount] = useState(0);
    const [big, setSize] = useState(true);
    const [type, setType] = useState("寬面");
    const size = (big)=>big? "大":"小";

    const {counter, add} = useContext(context)

    useEffect(() => {            
        add()
        return window.alert(`一共賣出${counter}碗💪💪💪💪`)
    }, [count])

    return (
        <div>
            <h3>麪館{props.shop}</h3>
            <h2>老闆,來{count}{size(big)}{type}</h2>
            <button onClick={()=> setCount(count+1)} style={{"height":"40px"}}>加一碗</button>
            <button onClick={()=> setSize(!big)} style={{"height":"40px"}}>{size(!big)}</button>
            <button onClick={()=> setType("細面")} style={{"height":"40px"}}>不想吃寬面</button>
        </div>
    );
}

3. 效果展示

在這裏插入圖片描述

功能跟之前完全相同。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章