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

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

用法示例:


import { useState } from 'react'
const Test = () => {
    const [count, setCount] = useState(0);
    return (
        <>
            <h1>點(diǎn)擊了{count}</h1>
            <button onClick={() => setCount(count + 1)}>+1</button>
        </>
    );
}
export default Test

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


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(() => {
    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(() => {
    
    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)化


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(() => {
    
},[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è)儲(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閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異肖粮,居然都是意外死亡孤页,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門涩馆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來行施,“玉大人允坚,你說我怎么就攤上這事《旰牛” “怎么了稠项?”我有些...
    開封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鲜结。 經(jīng)常有香客問我展运,道長,這世上最難降的妖魔是什么精刷? 我笑而不...
    開封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任拗胜,我火速辦了婚禮,結(jié)果婚禮上怒允,老公的妹妹穿的比我還像新娘埂软。我一直安慰自己,他們只是感情好纫事,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開白布勘畔。 她就那樣靜靜地躺著,像睡著了一般儿礼。 火紅的嫁衣襯著肌膚如雪咖杂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天蚊夫,我揣著相機(jī)與錄音诉字,去河邊找鬼。 笑死知纷,一個(gè)胖子當(dāng)著我的面吹牛壤圃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播琅轧,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼伍绳,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了乍桂?” 一聲冷哼從身側(cè)響起冲杀,我...
    開封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎睹酌,沒想到半個(gè)月后权谁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡憋沿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年旺芽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡采章,死狀恐怖运嗜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情悯舟,我是刑警寧澤担租,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站抵怎,受9級(jí)特大地震影響翩活,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜便贵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一菠镇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧承璃,春花似錦利耍、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至舷嗡,卻和暖如春轴猎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背进萄。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來泰國打工捻脖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人中鼠。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓可婶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親援雇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子矛渴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

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

  • 前言 Google Play應(yīng)用市場對(duì)于應(yīng)用的targetSdkVersion有了更為嚴(yán)格的要求。從 2018 年...
    申國駿閱讀 64,077評(píng)論 14 98
  • 《來,我們說說孤獨(dú)》 1·他們都在寫孤獨(dú) 一個(gè)詩人 如果 不說說 內(nèi)心的孤獨(dú) 不將孤獨(dú) 寫進(jìn)詩里 是不是很掉價(jià)呢 ...
    聽太陽升起閱讀 4,375評(píng)論 1 7
  • 自幼貧民窟長大的女子筐赔,僥幸多念了兩本書铣猩,枉以為可以與人平起平坐〈剑可是人生從來都是接力賽剂习,我們卻天真的當(dāng)成了百米沖刺...
    Leeanran閱讀 5,770評(píng)論 1 5
  • 云舒老師,姓甚名誰较沪,男的女的鳞绕,多大歲數(shù),這些我全然不知尸曼。之所以要寫寫云舒老師们何,完全是因?yàn)樗麑懙奈恼拢缫粋€(gè)巨大的磁...
    數(shù)豆者m閱讀 2,351評(píng)論 6 9
  • """1.個(gè)性化消息: 將用戶的姓名存到一個(gè)變量中控轿,并向該用戶顯示一條消息冤竹。顯示的消息應(yīng)非常簡單,如“Hello ...
    她即我命閱讀 2,888評(píng)論 0 5