最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解如何構(gòu)建自己的react hooks

 更新時間:2021年05月14日 10:35:53   作者:蚊子博客  
我們組的前端妹子在組內(nèi)分享時談到了 react 的鉤子,趁此機會我也對我所理解的內(nèi)容進行下總結(jié),方便更多的同學(xué)了解。在 React 的 v16.8.0 版本里添加了 hooks 的這種新的 API,我們非常有必要了解下他的使用方法,并能夠結(jié)合我們的業(yè)務(wù)編寫幾個自定義的 hooks。

1. 常用的一個 hooks

官方中提供了幾個內(nèi)置的鉤子,我們簡單了解下他們的用法。

1.1 useState: 狀態(tài)鉤子

需要更新頁面狀態(tài)的數(shù)據(jù),我們可以把他放到 useState 的鉤子里。例如點擊按鈕一下,數(shù)據(jù)加 1 的操作:

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

return (<>
    <p>{ count}</p>
    <button onClick = {
        () => setCount(count + 1)
    }> add 1 </button>
    </>
);

在 typescript 的體系中,count 的類型,默認就是當(dāng)前初始值的類型,例如上面例子中的變量就是 number 類型。如果我們想自定義這個變量的類型,可以在 useState 后面進行定義:

const [count, setCount] = useState<number | null>(null); // 變量count為number類型或者null類型

同時,使用 useState 改變狀態(tài)時,是整個把 state 替換掉的,因此,若狀態(tài)變量是個 object 類型的數(shù)據(jù),我只想修改其中的某個字段,在之前 class 組件內(nèi)調(diào)用 setState 時,他內(nèi)部會自動合并數(shù)據(jù)。

class Home extends React.Component {
    state = {
        name: 'wenzi',
        age: 20,
        score: 89
    };

    update() {
        this.setState({
            score: 98
        }); // 內(nèi)部自動合并
    }
}

但在 function 組件內(nèi)使用 useState 時,需要自己先合并數(shù)據(jù),然后再調(diào)用方法,否則會造成字段的丟失。

const [person, setPerson] = useState({
    name: 'wenzi',
    age: 20,
    score: 89
});

setPerson({
    ...person,
    {
        score: 98
    }
}); // 先合并數(shù)據(jù) { name: 'wenzi', age: 20, score: 98 }
setPerson({
    score: 98
}); // 僅傳入要修改的字段,后name和age字段丟失

1.2 useEffect: 副作用鉤子

useEffect 可以看做是 componentDidMount,componentDidUpdate 和 componentWillUnmount 這三個函數(shù)的組合。

useEffect 鉤子在組件初始化完畢時,一定會執(zhí)行一次,在組件重新渲染的過程中,是否還要 update,還要看傳入的第 2 個參數(shù)。

  • 當(dāng)只有回調(diào)函數(shù)這一個參數(shù)時,組件的每次更新,回調(diào)都會執(zhí)行;
  • 當(dāng)有 2 個參數(shù)時,只有第 2 參數(shù)里的數(shù)據(jù)發(fā)生變化時,回調(diào)才執(zhí)行;
  • 只想在組件初始化完畢時只執(zhí)行一次,第 2 個參數(shù)可以傳入一個空的數(shù)組;

我們可以看下這個例子,無論點擊 add按鈕 還是 settime按鈕 ,useEffect 的回調(diào)都會執(zhí)行:

const Home = () => {
    const [count, setCount] = useState(0);
    const [nowtime, setNowtime] = useState(0);

    useEffect(() => {
        console.log('count', count);
        console.log('nowtime', nowtime);
    });

    return ( <>
        <p>count: {count} </p>
        <p>nowtime: {nowtime} </p>
        <button onClick = {() => setCount(count + 1)}> add 1 </button>
        <button onClick = {() => setNowtime(Date.now())} > set now time </button>
    </>);
};

若改成下面的這樣,回調(diào)僅會在 count 發(fā)生變化時才會在控制臺輸出,僅修改 nowtime 的值時沒有輸出:

useEffect(() => {
    console.log('count', count);
    console.log('nowtime', nowtime);
}, [count]);

useEffect 的回調(diào)函數(shù)還可以返回一個函數(shù),這個函數(shù)在 effect 生命周期結(jié)束之前調(diào)用。為防止內(nèi)存泄漏,清除函數(shù)會在組件卸載前執(zhí)行。另外,如果組件多次渲染,則在執(zhí)行下一個 effect 之前,上一個 effect 就已被清除。

基于上面的代碼,我們稍微修改一下:

useEffect(() => {
    console.log('count', count);
    console.log('nowtime', nowtime);

    return () => console.log('effect callback will be cleared');
}, [count]);

基于這個機制,在一些存在添加綁定和取消綁定的案例上特別合適,例如監(jiān)聽頁面的窗口大小變化、設(shè)置定時器、與后端的 websocket 接口建立連接和斷開連接等,都可以預(yù)計 useEffect 進行二次的封裝,形成自定義的 hook。關(guān)于自定義 hook,下面我們會講到。

1.3 useMemo 和 useCallback

function 組件中定義的變量和方法,在組件重新渲染時,都會重新重新進行計算,例如下面的這個例子:

const Home = () => {
    const [count, setCount] = useState(0);
    const [nowtime, setNowtime] = useState(0);

    const getSum = () => {
        const sum = ((1 + count) * count) / 2;
        return sum + ' , ' + Math.random(); // 這個random是為了看到區(qū)別
    };

    return ( <>
        <p> count: {count}< /p>
        <p> sum: {getSum()}</p>
        <p> nowtime: {nowtime}</p>
        <button onClick = {() => setCount(count + 1)} > add 1 </button>
        <button onClick = {() => setNowtime(Date.now())}> set now time </button>
    </>);
};

這里有 2 個按鈕,一個是 count+1,一個設(shè)置當(dāng)前的時間戳, getSun() 方法是計算從 1 到 count 的和,我們每次點擊 add 按鈕后,sum 方法都會重新計算和。可是當(dāng)我們點擊 settime 按鈕時,getSum 方法也會重新計算,這是沒有必要的。

這里我們可以使用 useMemo 來修改下:

const sum = useMemo(() => ((1 + count) * count) / 2 + ' , ' + Math.random(), [count]);

<p> {sum} </p>;

修改后就可以看到,sum 的值只有在 count 發(fā)生變化的時候才重新計算,當(dāng)點擊 settime 按鈕的時候,sum 并沒有重新計算。這要得益于 useMemo 鉤子的特性:

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

useMemo 返回回調(diào)里 return 的值,而且 memoizedValue 它僅會在某個依賴項改變時才重新計算。這種優(yōu)化有助于避免在每次渲染時都進行高開銷的計算。如果沒有提供依賴項數(shù)組,useMemo 在每次渲染時都會計算新的值。

在上面的例子里,只有 count 變量發(fā)生變化時,才重新計算 sum,否則 sum 的值保持不變。

useCallback 與 useMemo 類型,只不過 useCallback 返回的是一個函數(shù),例如:

const fn = useCallback(() => {
    return ((1 + count) * count) / 2 + ' , ' + nowtime;
}, [count]);

2. 實現(xiàn)幾個自定義的 hook

在官方文檔里,實現(xiàn)了好友的在線與離線功能。這里我們自己也學(xué)著實現(xiàn)幾個 hook。

2.1 獲取窗口變化的寬高

我們通過監(jiān)聽resize事件來獲取實時獲取window窗口的寬高,對這個方法進行封裝后可以在生命周期結(jié)束前能自動解綁resize事件:

const useWinResize = () => {
    const [size, setSize] = useState({
        width: document.documentElement.clientWidth,
        height: document.documentElement.clientHeight
    });
    const resize = useCallback(() => {
        setSize({
        width: document.documentElement.clientWidth,
        height: document.documentElement.clientHeight
    })
    }, [])
    useEffect(() => {
        window.addEventListener('resize', resize);
        return () => window.removeEventListener('resize', resize);
    }, []);
    return size;
}

使用起來也非常方便:

const Home = () => {
    const {width, height} = useWinResize();

    return <div>
        <p>width: {width}</p>
        <p>height: {height}</p>
    </div>;
};

2.2 定時器 useInterval

在前端中使用定時器時,通常要在組件生命周期結(jié)束前清除定時器,如果定時器的周期發(fā)生變化了,還要先清除定時器再重新按照新的周期來啟動。這種最常用的場景就是九宮格抽獎,用戶點擊開始抽獎后,先緩慢啟動,然后逐漸變快,接口返回中獎結(jié)果后,再開始減速,最后停止。

我們很容易想到用 useEffect 來實現(xiàn)這樣的一個 hook:

const useInterval = (callback, delay) => {
    useEffect(() => {
        if (delay !== null) {
            let id = setInterval(callback, delay);
            return () => clearInterval(id);
        }
    }, [delay]);
};

我們把這段代碼用到項目中試試:

const Home = () => {
    const [count, setCount] = useState(0);

    useInterval(() => {
        console.log(count);
        setCount(count + 1);
    }, 500);

    return <div > {
        count
    } < /div>;
};

可是這段運行后很奇怪,頁面從 0 到 1 后,就再也不變了, console.log(count) 的輸出表明代碼并沒有卡死,那么問題出在哪兒了?

React 組件中的 props 和 state 是可以改變的, React 會重渲染它們且「丟棄」任何關(guān)于上一次渲染的結(jié)果,它們之間不再有相關(guān)性。

useEffect() Hook 也「丟棄」上一次渲染結(jié)果,它會清除上一次 effect 再建立下一個 effect,下一個 effect 鎖住新的 props 和 state,這也是我們第一次嘗試簡單示例可以正確工作的原因。

但 setInterval 不會「丟棄」。 它會一直引用老的 props 和 state 直到你把它換掉 —— 不重置時間你是無法做到的。

這里就要用到useRef這個 hook 了,我們把 callback 存儲到 ref 中,當(dāng) callback 更新時去更新 ref.current 的值:

const useInterval = (callback, delay) => {
    const saveCallback = useRef();

    useEffect(() => {
        // 每次渲染后,保存新的回調(diào)到我們的 ref 里
        saveCallback.current = callback;
    });

    useEffect(() => {
        function tick() {
            saveCallback.current();
        }
        if (delay !== null) {
            let id = setInterval(tick, delay);
            return () => clearInterval(id);
        }
    }, [delay]);
};

當(dāng)我們使用新的 useInterval 時,發(fā)現(xiàn)就可以自增了

這里我們使用一個變量來控制增加的速度:

const [count, setCount] = useState(0);
const [diff, setDiff] = useState(500);

useInterval(() => {
    setCount(count + 1);
}, diff);

return ( <div>
    <p> count: {count} </p>
    <p> diff: {diff}ms </p> 
    <p>
        <button onClick = {() => setDiff(diff - 50)}> 加快50ms </button> 
        <button onClick = {() => setDiff(diff + 50)} > 減慢50ms </button>
    </p>
</div>);

分別點擊兩個按鈕,可以調(diào)整count增加的速度。

3. 總結(jié)

使用react hook可以做很多有意思的事情,這里我們也僅僅是舉幾個簡單的例子,后續(xù)我們也會更加深入了解hook的原理。

以上就是如何構(gòu)建自己的 react hooks的詳細內(nèi)容,更多關(guān)于如何構(gòu)建自己的 react hooks的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 基于React封裝一個層次模糊效果的容器組件

    基于React封裝一個層次模糊效果的容器組件

    這篇文章主要為大家詳細介紹了如何基于React封裝一個層次模糊效果的容器組件,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • React受控組件與非受控組件實例分析講解

    React受控組件與非受控組件實例分析講解

    具體來說這是一種react非受控組件,其狀態(tài)是在input的react內(nèi)部控制,不受調(diào)用者控制??梢允褂檬芸亟M件來實現(xiàn)。下面就說說這個React中的受控組件與非受控組件的相關(guān)知識,感興趣的朋友一起看看吧
    2023-01-01
  • React hooks的優(yōu)缺點詳解

    React hooks的優(yōu)缺點詳解

    這篇文章主要介紹了React hooks的優(yōu)缺點詳解,幫助大家更好的理解和學(xué)習(xí)使用React,感興趣的朋友可以了解下
    2021-04-04
  • React18+TS通用后臺管理系統(tǒng)解決方案落地實戰(zhàn)示例

    React18+TS通用后臺管理系統(tǒng)解決方案落地實戰(zhàn)示例

    這篇文章主要為大家介紹了React18+TS通用后臺管理系統(tǒng)解決方案落地實戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • react+react-beautiful-dnd實現(xiàn)代辦事項思路詳解

    react+react-beautiful-dnd實現(xiàn)代辦事項思路詳解

    這篇文章主要介紹了react+react-beautiful-dnd實現(xiàn)代辦事項,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • React+Mobx基本使用、模塊化操作

    React+Mobx基本使用、模塊化操作

    React 和 MobX 是一對強力組合,React 通過提供機制把應(yīng)用狀態(tài)轉(zhuǎn)換為可渲染組件樹并對其進行渲染,而MobX提供機制來存儲和更新應(yīng)用狀態(tài)供 React 使用,這篇文章主要介紹了React+Mobx基本使用、模塊化,需要的朋友可以參考下
    2022-09-09
  • react中使用swiper的具體方法

    react中使用swiper的具體方法

    本篇文章主要介紹了react中使用swiper的具體方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • react-three-fiber實現(xiàn)炫酷3D粒子效果首頁

    react-three-fiber實現(xiàn)炫酷3D粒子效果首頁

    這篇文章主要介紹了react-three-fiber實現(xiàn)3D粒子效果,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-08-08
  • 使用Node搭建reactSSR服務(wù)端渲染架構(gòu)

    使用Node搭建reactSSR服務(wù)端渲染架構(gòu)

    這篇文章主要介紹了使用Node搭建reactSSR服務(wù)端渲染架構(gòu),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • React使用setState更新數(shù)組的方法示例(追加新數(shù)據(jù))

    React使用setState更新數(shù)組的方法示例(追加新數(shù)據(jù))

    在?React?中,setState?是管理組件狀態(tài)的核心方法之一,然而,當(dāng)我們需要更新狀態(tài)中的數(shù)組時,如何高效且安全地操作變得尤為關(guān)鍵,本文將詳細解析以下代碼的實現(xiàn)邏輯,幫助你掌握在?React?中追加數(shù)組數(shù)據(jù)的最佳實踐,需要的朋友可以參考下
    2025-03-03

最新評論

东乡族自治县| 荃湾区| 桦南县| 衡阳县| 来宾市| 涞水县| 乐陵市| 大竹县| 静海县| 吉水县| 左权县| 志丹县| 县级市| 辽源市| 民权县| 驻马店市| 邯郸市| 土默特左旗| 宁强县| 山西省| 通许县| 宁南县| 玉溪市| 扬州市| 汝南县| 莒南县| 全南县| 大同市| 民勤县| 延津县| 广丰县| 上杭县| 连江县| 陈巴尔虎旗| 六安市| 泊头市| 恩平市| 讷河市| 当雄县| 闽侯县| 台南市|