欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

React中useState和useEffect的用法詳解

 更新時(shí)間:2023年06月16日 09:46:59   作者:何遇er  
Hooks?發(fā)布之后,函數(shù)組件能擁有自己的?state,React提供了很多內(nèi)置的Hooks,這篇文章就來(lái)和大家介紹一下useState?和?useEffect的使用,需要的可以參考一下

之前在不討論 React Hooks 和組件生命周期的基礎(chǔ)上介紹了函數(shù)組件和類(lèi)組件的差別,現(xiàn)在介紹一個(gè)為函數(shù)組件而生的知識(shí)點(diǎn),即:React Hooks。Hooks 是函數(shù),在 React 16.8 正式發(fā)布,它對(duì)類(lèi)組件沒(méi)有影響。

類(lèi)組件的功能強(qiáng)大,能擁有自己的state,有生命周期,開(kāi)發(fā)人員能根據(jù)需求在特定的生命周期中執(zhí)行自己要想的操作,如:發(fā)送Ajax請(qǐng)求等。類(lèi)組件功能雖強(qiáng),但它存在如下問(wèn)題:

1.必須時(shí)常關(guān)注 this 關(guān)鍵字的指向,這對(duì)初學(xué)者而言不是一件容易的事。

2.相同的生命周期函數(shù)在類(lèi)組件中最多定義一個(gè),這導(dǎo)致彼此無(wú)關(guān)的邏輯代碼被揉雜在同一生命周期函數(shù)中。

3.不同的生命周期函數(shù)可能包含相同的代碼,最常見(jiàn)便是 componentDidMount 和 componentDidUpdate。

Hooks 發(fā)布之后,函數(shù)組件能擁有自己的 state,也能感知到組件被銷(xiāo)毀和 DOM 被繪制到屏幕上的時(shí)機(jī),但是沒(méi)有類(lèi)組件存在的那三個(gè)問(wèn)題。React提供了很多內(nèi)置的Hooks,在本文介紹 useState 和 useEffect。

useState

它是一個(gè)與狀態(tài)管理相關(guān)的hook,它讓函數(shù)組件擁有狀態(tài),是最常用的Hooks之一,類(lèi)型定義如下:

function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
function useState<S = undefined>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>];

從類(lèi)型定義可以看出,useState 有兩個(gè)重載,分別是傳參數(shù)和不傳參數(shù),不論是否傳參數(shù),useState 都返回一個(gè)長(zhǎng)度為 2 的數(shù)組,數(shù)組的第一個(gè)位置是狀態(tài),它可以是任何數(shù)據(jù)類(lèi)型,類(lèi)型參數(shù) S 用于注釋它的類(lèi)型,第二個(gè)位置是一個(gè)用于更新?tīng)顟B(tài)的函數(shù),為了語(yǔ)言上的便利本小節(jié)將該函數(shù)記為 setState。接下來(lái),介紹 useState 的基本用法。

當(dāng) useState 的參數(shù)不是函數(shù)

此時(shí),useState 的參數(shù)作為狀態(tài)的初始值,如果沒(méi)有傳參數(shù),那么狀態(tài)的初始值為 undefined。用法如下:

import React, { useState } from 'react'
export function UseStateWithoutFunc() {
    const [name, setName] = useState<string>('何遇')
    const [age, setAge] = useState<number>()
    function onChange() {
        setName(Math.random() + '') // 修改name
        setAge(Math.random()) // 修改age
    }
    return (
        <>
        <div>姓名: {name}</div>
        <div>年齡: {age === undefined ? '未知' : age}</div>
        <button onClick={onChange}>click</button>
        </>
    )
}

UseStateWithoutFunc 組件有 name 和 age 這兩個(gè)狀態(tài),name 只能是 string 類(lèi)型,初始值為'何遇',age 的數(shù)據(jù)類(lèi)型是 number 或 undefined,初始值為undefined。

當(dāng) useState 的參數(shù)是函數(shù)

此時(shí),函數(shù)的返回值是狀態(tài)的初始值。某些時(shí)候,狀態(tài)的初始值要經(jīng)過(guò)計(jì)算才能得到,此時(shí)推薦將函數(shù)作為 useState 的參數(shù),該函數(shù)只在組件初始渲染執(zhí)行一次。用法如下:

function UseStateWithFunc() {
    const [count, setCount] = useState<number>(() => {
        // 這個(gè)函數(shù)只在初始渲染的時(shí)候執(zhí)行,后續(xù)的重新渲染不再執(zhí)行
        return Number(localStorage.getItem('count')) || 0
    })
    function onChange() {/** todo*/}
    return (
        <>
        <div>count: {count}</div>
        <button onClick={onChange}>click</button>
        </>
    )
}

上述 useState 的參數(shù)是函數(shù),count 的初始值為該函數(shù)的返回值,數(shù)據(jù)類(lèi)型是 number。

修改狀態(tài)的值

延用上述代碼中的 setCount,修改狀態(tài)有兩種方式。用法如下:

// 用法一
setCount((count) => {
   return count + 1
})
// 用法二
setCount(0)

如果 setCount 的參數(shù)是函數(shù),那么 count 現(xiàn)在的值將以參數(shù)的形式傳給該函數(shù),函數(shù)的返回值用于更新?tīng)顟B(tài)。如果 setCount 的參數(shù)不是函數(shù),那么該參數(shù)將用于更新?tīng)顟B(tài)。修改狀態(tài)只能使用與它相關(guān)的 setState ,且必須滿(mǎn)足 Immutability 原則,狀態(tài)值發(fā)生變更將導(dǎo)致組件重新渲染,重新渲染時(shí),useState 返回的第一個(gè)值始終是狀態(tài)最新的值,不會(huì)重置為初始值。

目前已介紹完 useState 的基本用法,觀(guān)察下面這段更復(fù)雜的代碼,分析瀏覽器打印的結(jié)果。

function UseStateAdvanceDemo() {
    // count 的初始值為 0
    const [count, setCount] = useState<number>(0)
    const onClick = () => {
        setCount((prevCount) => prevCount + 1) // 將count在原來(lái)的基礎(chǔ)上加1
        setTimeout(() => {
            console.log(count) // 分析瀏覽器打印的結(jié)果
        }, 1000)
    }
    return <button onClick={onClick}>打開(kāi)開(kāi)發(fā)者工具再點(diǎn)擊</button>
}

如果你理解了React 的函數(shù)組件中介紹的知識(shí),那么能輕而易舉的分析出瀏覽器打印的值為0而不是1。再?gòu)?qiáng)調(diào)一次,在函數(shù)組件中取 state 和 props 拿到的都是本次渲染的值,在本次渲染范圍內(nèi),props 和 state 始終不變。在上述代碼中,調(diào)用 setCount 會(huì)導(dǎo)致組件重新渲染,在下一次渲染時(shí) count 的值為 1,但 console.log(count) 打印的是本次渲染時(shí) count 的值,所以結(jié)果為 0。

useEffect

useEffect 是除 useState 之外另一個(gè)常用的 Hook,它比 useState 的理解難度更大,但只要你明白函數(shù)組件每次渲染都有它自己的 state 和 props,那么理解useEffect 將變得容易。使用 useEffect 能讓開(kāi)發(fā)人員知道 DOM 什么時(shí)候被繪制到了屏幕,組件什么時(shí)候被銷(xiāo)毀了,有些開(kāi)發(fā)人員認(rèn)為它是類(lèi)組件 componentDidMount、componentDidUpdate 和 componentWillUnmount 生命周期函數(shù)的結(jié)合,但實(shí)際上函數(shù)組件沒(méi)有與類(lèi)組件類(lèi)似的生命周期概念。

useEffect 類(lèi)型定義如下:

type EffectCallback = () => (void | Destructor);
function useEffect(effect: EffectCallback, deps?: DependencyList): void;

從類(lèi)型定義可以看出,useEffect 最多接受兩個(gè)參數(shù),第一個(gè)參數(shù)是函數(shù),可以有返回值,之后將該函數(shù)稱(chēng)為 effect;第二個(gè)參數(shù)非必填,是個(gè)數(shù)組,它是 effect 的依賴(lài),稱(chēng)為 deps。deps 用于確定 effect 在本次渲染是否執(zhí)行,如果執(zhí)行,那么在瀏覽器將 DOM 繪制到屏幕之后執(zhí)行,可以將 Ajax 請(qǐng)求,訪(fǎng)問(wèn) DOM 等操作放在effect 中,它不會(huì)阻塞瀏覽器繪制。函數(shù)組件可以多次使用 useEffect,每使用一次就定義一個(gè) effect,這些 effect 的執(zhí)行順序與它們被定義的順序一致,建議將不同職責(zé)的代碼放在不同的 effect 中。接下來(lái)從 effect 的清理工作和它的依賴(lài)這兩個(gè)方面介紹 useEffect。

effect沒(méi)有清理工作

effect 沒(méi)有清理工作就意味著它沒(méi)有返回值,代碼如下:

function EffectWithoutCleanUp() {
    const [name, setTitle] = useState<string>('何遇')
    useEffect(() => {
        document.title = name
    })
    return (
      	// something
    )
}

上述代碼定義了一個(gè) effect,它的作用是將 document.title 設(shè)置成本次渲染時(shí) name 的值。

effect 有清理工作

effect 的清理工作指 effect 返回的函數(shù),該函數(shù)在組件重新渲染后和組件卸載時(shí)被調(diào)用,下面的代碼定義了一個(gè)有清理工作的 effect。

function EffectWithCleanUp() {
    const [name, setTitle] = useState<string>('何遇')
    useEffect(() => {
        const onBodyClick = () => {/** todo */}
        document.body.addEventListener('click', onBodyClick)
        // 在返回的函數(shù)中定義與該effect相關(guān)的清理工作
        return () => {
            document.body.removeEventListener('click', onBodyClick)
        }
    })
    return (
        // something
    )
}

上述 effect 在 DOM 被繪制到界面之后給 body 元素綁定 click 事件,組件重新渲染之后將上一次 effect 綁定的 click 事件解綁。該 effect 在組件首次渲染和之后的每次重新渲染都將執(zhí)行,如果組件的狀態(tài)更新頻繁,那么組件重新渲染也會(huì)很頻繁,這導(dǎo)致 body 頻繁綁定 click 事件又解綁 click事件。是否有辦法使組件只在首次渲染時(shí)給 body 綁定事件呢?當(dāng)然有。

effect 的依賴(lài)

前面兩個(gè)示例定義的 effect 沒(méi)有指明依賴(lài),因此組件每一輪渲染都會(huì)執(zhí)行它們。下面的代碼讓組件只在首次渲染時(shí)給 body 綁定事件,代碼如下:

useEffect(() => {
        const onBody = () => {/** todo */}
        document.body.addEventListener('click', onBody)
        return () => {
            // 在組件卸載時(shí)將事件解綁
            document.body.removeEventListener('click', onBody)
        }
}, [])

給 useEffect 第二個(gè)參數(shù)傳空數(shù)據(jù)意味著 effect 沒(méi)有依賴(lài),該 effect 只在組件初始渲染時(shí)執(zhí)行,它的清理工作在組件卸載時(shí)執(zhí)行。對(duì)于綁定 DOM 事件而言這是一件好事,它可以防止事件反復(fù)綁定和解綁,但問(wèn)題是,如果在事件處理程序中訪(fǎng)問(wèn)組件的 state 和 props,那么只能拿到它們的初始值,拿不到最新的值。是否有辦法讓 effect 始終拿到 state 和 props 最新的值呢?有。

給 effect 傳遞依賴(lài)項(xiàng),React 會(huì)將本次渲染時(shí)依賴(lài)項(xiàng)的值與上一次渲染時(shí)的值進(jìn)行淺對(duì)比,如果結(jié)論是它們其中之一有變化,那么該 effect 會(huì)被執(zhí)行,否則不會(huì)執(zhí)行。為了讓 effect 拿到它所需 state 和 props 的最新值,effect 中所有要訪(fǎng)問(wèn)的外部變量都應(yīng)該作為依賴(lài)項(xiàng)放在 useEffect 第二個(gè)參數(shù)中。代碼如下:

useEffect(() => {
       const onBody = () => {
       console.log(name) // 始終得到最新的name值
    }
        document.body.addEventListener('click', onBody)
        return () => {
            document.body.removeEventListener('click', onBody)
        }
}, [name])

上述 effect 在組件初始渲染會(huì)執(zhí)行,當(dāng) name 發(fā)生變化導(dǎo)致組件重新渲染也會(huì)執(zhí)行,相應(yīng)的,組件卸載時(shí)和由 name 變化導(dǎo)致組件渲染之后將清理上一個(gè) effect。

提示:函數(shù)組件每次渲染時(shí),effect 都是一個(gè)不同的函數(shù),在函數(shù)組件內(nèi)的每一個(gè)位置(包括事件處理函數(shù),effects,定時(shí)器等等)只能拿到定義它們的那次渲染的 props 和 state。

函數(shù)組件生命周期內(nèi) hooks 的調(diào)用順序如下圖

以上就是React中useState和useEffect的用法詳解的詳細(xì)內(nèi)容,更多關(guān)于React useState useEffect的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • React路由的history對(duì)象的插件history的使用解讀

    React路由的history對(duì)象的插件history的使用解讀

    這篇文章主要介紹了React路由的history對(duì)象的插件history的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • 如何將你的AngularJS1.x應(yīng)用遷移至React的方法

    如何將你的AngularJS1.x應(yīng)用遷移至React的方法

    本篇文章主要介紹了如何將你的AngularJS1.x應(yīng)用遷移至React的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • react組件傳值的四種方法

    react組件傳值的四種方法

    本文主要介紹了react組件傳值的四種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • react使用axios進(jìn)行api網(wǎng)絡(luò)請(qǐng)求的封裝方法詳解

    react使用axios進(jìn)行api網(wǎng)絡(luò)請(qǐng)求的封裝方法詳解

    這篇文章主要為大家詳細(xì)介紹了react使用axios進(jìn)行api網(wǎng)絡(luò)請(qǐng)求的封裝方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03
  • 你知道怎么基于?React?封裝一個(gè)組件嗎

    你知道怎么基于?React?封裝一個(gè)組件嗎

    這篇文章主要為大家詳細(xì)介紹了React如何封裝一個(gè)組件,使用antd的divider組件來(lái)講解,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • React通過(guò)useContext特性實(shí)現(xiàn)組件數(shù)據(jù)傳遞

    React通過(guò)useContext特性實(shí)現(xiàn)組件數(shù)據(jù)傳遞

    本文主要介紹了React如何通過(guò)useContext特性實(shí)現(xiàn)組件數(shù)據(jù)傳遞,文中有相關(guān)的代碼示例供大家參考,對(duì)我們學(xué)習(xí)React有一定的幫助,需要的朋友可以參考下
    2023-06-06
  • react-redux的connect與React.forwardRef結(jié)合ref失效的解決

    react-redux的connect與React.forwardRef結(jié)合ref失效的解決

    這篇文章主要介紹了react-redux的connect與React.forwardRef結(jié)合ref失效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • 再次談?wù)揜eact.js實(shí)現(xiàn)原生js拖拽效果引起的一系列問(wèn)題

    再次談?wù)揜eact.js實(shí)現(xiàn)原生js拖拽效果引起的一系列問(wèn)題

    React 起源于 Facebook 的內(nèi)部項(xiàng)目,因?yàn)樵摴緦?duì)市場(chǎng)上所有 JavaScript MVC 框架,都不滿(mǎn)意,就決定自己寫(xiě)一套,用來(lái)架設(shè) Instagram 的網(wǎng)站.本文給大家介紹React.js實(shí)現(xiàn)原生js拖拽效果,需要的朋友一起學(xué)習(xí)吧
    2016-04-04
  • 關(guān)于react+antd樣式不生效問(wèn)題的解決方式

    關(guān)于react+antd樣式不生效問(wèn)題的解決方式

    最近本人在使用Antd開(kāi)發(fā)時(shí)遇到些問(wèn)題,所以下面這篇文章主要給大家介紹了關(guān)于react+antd樣式不生效問(wèn)題的解決方式,文中通過(guò)圖文以及實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07
  • React?+?Typescript領(lǐng)域初學(xué)者的常見(jiàn)問(wèn)題和技巧(最新)

    React?+?Typescript領(lǐng)域初學(xué)者的常見(jiàn)問(wèn)題和技巧(最新)

    這篇文章主要介紹了React?+?Typescript領(lǐng)域初學(xué)者的常見(jiàn)問(wèn)題和技巧,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06

最新評(píng)論