React Hook用法詳解(6個(gè)常見hook)

1、useState:讓函數(shù)式組件擁有狀態(tài)

用法示例:

// 計(jì)數(shù)器
import { useState } from 'react'
const Test = () => {
    const [count, setCount] = useState(0);
    return (
        <>
            <h1>點(diǎn)擊了{(lán)count}次</h1>
            <button onClick={() => setCount(count + 1)}>+1</button>
        </>
    );
}
export default Test

PS:class組件中this.setState更新是state是合并欣福, useState中setState是替換。例如:

// 錯(cuò)誤示例
import { useState } from 'react'
const Test = () => {
    const [counts, setCounts] = useState({
        num1: 0,
        num2: 0
    });
    return (
        <>
            <h1>num1:{counts.num1}</h1>
            <h1>num2:{counts.num2}</h1>
            <button onClick={() => setCounts({ num1: counts.num1 + 1})}>num1+1</button>
            <button onClick={() => setCounts({ num2: counts.num2 + 1})}>num2+1</button>
        </>
    );
}
export default Test

可以看到useState中setState是替換,不會(huì)合并,正確更新:

import { useState } from 'react'
const Test = () => {
    const [counts, setCounts] = useState({
        num1: 0,
        num2: 0
    });
    return (
        <>
            <h1>num1:{counts.num1}</h1>
            <h1>num2:{counts.num2}</h1>
            <button onClick={() => setCounts({ ...counts, num1: counts.num1 + 1})}>num1+1</button>
            <button onClick={() => setCounts({ ...counts, num2: counts.num2 + 1})}>num2+1</button>
        </>
    );
}
export default Test

2慷妙、useEffect:副作用,取代生命周期

用法示例允悦,在class組件中如果需要在組件掛載后和數(shù)據(jù)更新后做同一件事,我們會(huì)這樣做:

componentDidMount() {
    // 做一些事
}
componentDidUpdate() {
    // 做一些事
}

可以看出來虑啤,如果邏輯復(fù)雜后隙弛,代碼看起來不優(yōu)雅,且容易造成邏輯混亂狞山,而使用useEffect:

useEffect(() => {
    // 做一些事
});

此刻已經(jīng)看到了useEffect的基本用法全闷,除此之外,他還可以綁定觸發(fā)更新的依賴狀態(tài)萍启,默認(rèn)是狀態(tài)中任何數(shù)據(jù)發(fā)生變化副作用都會(huì)執(zhí)行总珠,如:

import { useState, useEffect } from 'react'
const Test = () => {
    const [count1, setCount1] = useState(0);
    const [count2, setCount2] = useState(0);
    useEffect(() => {
        console.log('useEffect觸發(fā)了')
    });
    return (
        <>
            <h1>count1:{count1}</h1>
            <h1>count2:{count2}</h1>
            <button onClick={() => setCount1(count1 + 1)}>count1+1</button>
            <button onClick={() => setCount2(count2 + 1)}>count2+1</button>
        </>
    );
}
export default Test

將上述代碼useEffect第二個(gè)參數(shù)傳入需要綁定的狀態(tài),可綁定多個(gè):

// 語法:useEffect(回調(diào)函數(shù)勘纯,[依賴值])
useEffect(() => {
    console.log('useEffect觸發(fā)了')
}, [count1]);

可以看到局服,只有綁定的count1發(fā)生變化才會(huì)觸發(fā),如果傳空數(shù)組則任何狀態(tài)發(fā)生變化都不會(huì)觸發(fā)驳遵,此時(shí)useEffect的作用就類似class組件中的componentDidMount淫奔,所以發(fā)送請(qǐng)求通常也會(huì)在此執(zhí)行。

清理副作用
在上面的操作中都不用清理的副作用堤结,然而唆迁,有些副作用是需要去清理的,不清理會(huì)造成異常甚至內(nèi)存泄漏竞穷,比如開啟定時(shí)器唐责,如果不清理,則會(huì)多次開啟瘾带,從上面可以看到useEffect的第一個(gè)參數(shù)是一個(gè)回調(diào)函數(shù)鼠哥,可以在回調(diào)函數(shù)中再返回一個(gè)函數(shù),該函數(shù)可以在狀態(tài)更新后第一個(gè)回調(diào)函數(shù)執(zhí)行之前調(diào)用看政,具體實(shí)現(xiàn):

seEffect(() => {
    // 設(shè)置副作用
    return () => {
        // 清理副作用
    }
});

3肴盏、useContext:跨組件共享數(shù)據(jù)

React.createContext();創(chuàng)建一個(gè)TestContext對(duì)象
TestContext.Provider包裹子組件
數(shù)據(jù)放在<TestContext.Provider value={value}>的value中
子組件中通過useContext(TestContext)獲取值

import React, { useContext, useState } from 'react';
const TestContext = React.createContext();
const Parent = () => {
    const [value, setValue] = useState(0);
    return (
        <div>
            {(() => console.log("Parent-render"))()}
            <button onClick={() => setValue(value + 1)}>value + 1</button>
            <TestContext.Provider value={value}>
                <Child1 />
                <Child2 />
            </TestContext.Provider>
        </div>
    );
}
const Child1 = () => {
    const value = useContext(TestContext);
    return (
        <div>
            {(() => console.log('Child1-render'))()}
            <h3>Child1-value: {value}</h3>
        </div>
    );
}
const Child2 = () => {
    return (
        <div>
            {(() => console.log('Child2-render'))()}
            <h3>Child2</h3>
        </div>
    );
}
export default Parent

至此數(shù)據(jù)實(shí)現(xiàn)共享了,但是可以看到在TestContext中的共享數(shù)據(jù)只要發(fā)生變化帽衙,子組件都會(huì)重新渲染菜皂,Child2并沒有綁定數(shù)據(jù),不希望他做無意義的渲染厉萝,可以使用React.memo解決恍飘,實(shí)現(xiàn):

const Child2 = React.memo(() => {
    return (
        <div>
            {(() => console.log('Child2-render'))()}
            <h3>Child2</h3>
        </div>
    );
});

4榨崩、useCallback:性能優(yōu)化

// useCallback(回調(diào)函數(shù),[依賴值])
const handleClick = useCallback(()=> {
    // 做一些事
}, [value]);

useCallback返回的是一個(gè) memoized(緩存)函數(shù)章母,在依賴不變的情況下,多次定義的時(shí)候,返回的值是相同的母蛛,他的實(shí)現(xiàn)原理是當(dāng)使用一組參數(shù)初次調(diào)用函數(shù)時(shí),會(huì)緩存參數(shù)和計(jì)算結(jié)果乳怎,當(dāng)再次使用相同的參數(shù)調(diào)用該函數(shù)時(shí)彩郊,會(huì)直接返回相應(yīng)的緩存結(jié)果。

優(yōu)化性能例子:

import React, { useState, useCallback, memo } from 'react';
const Parent = () => {
    const [value1, setValue1] = useState(0);
    const [value2, setValue2] = useState(0);
    const handleClick1 = useCallback(()=> {
        setValue1(value1 + 1);
    }, [value1]);
    const handleClick2 = useCallback(()=> {
        setValue2(value2 + 1);
    }, [value2]);
    return (
        <>
            {(() => console.log("Parent-render"))()}
            <h3>{value1}</h3>
            <h3>{value2}</h3>
            <Child1 handleClick1={handleClick1} />
            <Child2 handleClick2={handleClick2} />
        </>
    );
}
const Child1 = memo(props => {
    return (
        <div>
            {(() => console.log("Child1-render"))()}
            <button onClick={() => props.handleClick1()}>value1 + 1</button>
        </div>
    );
});
const Child2 = memo(props => {
    return (
        <div>
            {(() => console.log("Child2-render"))()}
            <button onClick={() => props.handleClick2()}>value2 + 1</button>
        </div>
    );
});
export default Parent

useCallback返回的是一個(gè)memoized回調(diào)函數(shù)蚪缀,僅在其中綁定的一個(gè)依賴項(xiàng)變化后才更改可防止不必要的渲染秫逝,在跨組件共享數(shù)據(jù)中舉例的事件是在父組件中點(diǎn)擊觸發(fā),而現(xiàn)在是使用狀態(tài)提升询枚,在父組件中傳遞方法供子組件調(diào)用违帆,每次render時(shí)函數(shù)也會(huì)變化,導(dǎo)致子組件重新渲染金蜀,上面例子useCallback將函數(shù)進(jìn)行包裹刷后,依賴值未發(fā)生變化時(shí)會(huì)返回緩存的函數(shù),配合React.memo即可優(yōu)化無意義的渲染渊抄。

5尝胆、useMemo:性能優(yōu)化

語法:

// useMemo(回調(diào)函數(shù),[依賴值])
useMemo(() => {
    // 做一些事情
},[value]);

先看一個(gè)例子:

import React, { useState } from 'react'
const Test = ()=> {
    const [value, setValue] = useState(0);
    const [count, setCount] = useState(1);
    const getDoubleCount = () => {
        console.log('getDoubleCount進(jìn)行計(jì)算了');
        return count * 2;
    };
    return (
        <div>
            <h2>value: {value}</h2>
            <h2>doubleCount: {getDoubleCount()}</h2>
            <button onClick={() => setValue(value + 1)}>value+1</button>
        </div>
    )
}
export default Test

可以看到getDoubleCount依賴的是count护桦,但value發(fā)生變化它也重新進(jìn)行了計(jì)算渲染班巩,現(xiàn)在只需要將getDoubleCount使用useMemo進(jìn)行包裹,如下:

import React, { useState, useMemo } from 'react'
const Test = ()=> {
    const [value, setValue] = useState(0);
    const [count, setCount] = useState(1);
    const getDoubleCount = useMemo(() => {
        console.log('getDoubleCount進(jìn)行計(jì)算了');
        return count * 2;
    },[count]);
    return (
        <div>
            <h2>value: {value}</h2>
            <h2>doubleCount: {getDoubleCount}</h2>
            <button onClick={() => setValue(value + 1)}>value+1</button>
        </div>
    )
}
export default Test

現(xiàn)在getDoubleCount只有依賴的count發(fā)生變化時(shí)才會(huì)重新計(jì)算渲染嘶炭。

useMemo和useCallback的共同點(diǎn):

接收的參數(shù)都是一樣的抱慌,第一個(gè)是回調(diào)函數(shù),第二個(gè)是依賴的數(shù)據(jù)
它們都是當(dāng)依賴的數(shù)據(jù)發(fā)生變化時(shí)才會(huì)重新計(jì)算結(jié)果眨猎,起到了緩存作用

useMemo和useCallback的區(qū)別:

useMemo計(jì)算結(jié)果是return回來的值抑进,通常用于緩存計(jì)算結(jié)果的值
useCallback計(jì)算結(jié)果是一個(gè)函數(shù),通常用于緩存函數(shù)

6睡陪、useRef

用法:例如要實(shí)現(xiàn)點(diǎn)擊button按鈕使input輸入框獲得焦點(diǎn):

import React, { useRef } from 'react';
const Test = () => {
    const inputEl = useRef();
    return (
        <>
            <input ref={inputEl} />
            <button onClick={() => inputEl.current.focus()}>focus</button>
        </>
    );
}
export default Test

這樣看起來非常像React.createRef()寺渗,將上面代碼中的useRef()改成React.createRef()也能實(shí)現(xiàn)同樣的效果,那為什么要設(shè)計(jì)一個(gè)新的hook兰迫?難道只是為了加上use信殊,統(tǒng)一hook規(guī)范?
事實(shí)上汁果,它們確實(shí)不一樣涡拘。

官網(wǎng)的說明如下:

useRef returns a mutable ref object whose .current property is initialized to the passed
argument (initialValue). The returned object will persist for the full lifetime of the component.
//useRef返回一個(gè)可變的ref對(duì)象,其.current屬性初始化為傳遞的參數(shù)(initialValue)据德。返回的對(duì)象將在組件的整個(gè)生存期內(nèi)保持鳄乏。

簡(jiǎn)單來說跷车,useRef就像一個(gè)儲(chǔ)物箱,你可以隨意存放任何東西橱野,再次渲染時(shí)它會(huì)去儲(chǔ)物箱找朽缴,createRef每次渲染都會(huì)返回一個(gè)新的引用,而useRef每次都會(huì)返回相同的引用水援。

摘自:https://www.cnblogs.com/hymenhan/archive/2021/04/28/14711516.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末密强,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蜗元,更是在濱河造成了極大的恐慌或渤,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件许帐,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡毕谴,警方通過查閱死者的電腦和手機(jī)成畦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涝开,“玉大人循帐,你說我怎么就攤上這事∫ㄎ洌” “怎么了拄养?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)银舱。 經(jīng)常有香客問我瘪匿,道長(zhǎng),這世上最難降的妖魔是什么寻馏? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任棋弥,我火速辦了婚禮,結(jié)果婚禮上诚欠,老公的妹妹穿的比我還像新娘顽染。我一直安慰自己,他們只是感情好轰绵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布粉寞。 她就那樣靜靜地躺著,像睡著了一般左腔。 火紅的嫁衣襯著肌膚如雪唧垦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天液样,我揣著相機(jī)與錄音业崖,去河邊找鬼野芒。 笑死,一個(gè)胖子當(dāng)著我的面吹牛双炕,可吹牛的內(nèi)容都是我干的狞悲。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼妇斤,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼摇锋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起站超,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤荸恕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后死相,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體融求,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年算撮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了生宛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肮柜,死狀恐怖陷舅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情审洞,我是刑警寧澤莱睁,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站芒澜,受9級(jí)特大地震影響仰剿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜痴晦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一酥馍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧阅酪,春花似錦旨袒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至辉词,卻和暖如春必孤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工敷搪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留兴想,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓赡勘,卻偏偏與公主長(zhǎng)得像嫂便,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子闸与,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 1.useState useState可以讓函數(shù)組件擁有自己的一個(gè)狀態(tài),和class組件一樣去控制組件內(nèi)部數(shù)據(jù)的一...
    陳永龍閱讀 365評(píng)論 0 0
  • useState 使用狀態(tài) const [n, setN] = React.useState(0)const [u...
    改革路上最靚的崽閱讀 2,586評(píng)論 3 2
  • 1 關(guān)于hook 1.1 為什么使用hook 在react類組件(class)寫法中毙替,有setState和生命周期...
    江湖yi山人閱讀 1,849評(píng)論 0 3
  • React Hook是React函數(shù)式組件,它不僅僅有函數(shù)組件的特性践樱,還帶有React框架的特性厂画。所以,官網(wǎng)文檔多...
    娜姐聊前端閱讀 445評(píng)論 3 1
  • 一拷邢、組件類 React的核心是組件, 在v16.8之前,組件的標(biāo)準(zhǔn)寫法是類(class)袱院。 以下為一個(gè)簡(jiǎn)單的組件類...
    郭_小青閱讀 710評(píng)論 1 5