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

淺談react useEffect閉包的坑

 更新時(shí)間:2021年06月08日 16:07:48   作者:Saitmob  
筆者最近用react useEffect閉包,其中踩到了一些坑在此與大家分享一下。需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

問(wèn)題代碼

看一段因?yàn)閡seEffect導(dǎo)致的閉包問(wèn)題代碼

const btn = useRef();
const [v, setV] = useState('');

useEffect(() => {
    let clickHandle = () => {
        console.log('v:', v);
    }
    btn.current.addEventListener('click', clickHandle)
    
    return () => {
        btn.removeEventListener('click', clickHandle)
    }
}, []);
    
const inputHandle = e => {
    setV(e.target.value)
}

return (
        <>
            <input value={v} onChange={inputHandle} />
            <button ref={btn} >測(cè)試</button>
        </>
    )

useEffect的依賴項(xiàng)數(shù)組為空,所以在頁(yè)面渲染完成之后,內(nèi)部代碼只會(huì)執(zhí)行一次,頁(yè)面銷毀再執(zhí)行一次。此時(shí)在輸入框中輸入任意字符,再點(diǎn)擊測(cè)試按鈕,得到的輸出為空,之后無(wú)論如何輸入任何字符,再點(diǎn)擊測(cè)試按鈕時(shí),輸出的結(jié)果仍為空。

為什么會(huì)這樣呢?其實(shí)就是閉包所造成的。

產(chǎn)生原因

函數(shù)的作用域在函數(shù)定義的時(shí)候就決定了

給btn注冊(cè)點(diǎn)擊事件時(shí),作用域如下:

能訪問(wèn)到的自由變量v此時(shí)還是空值。當(dāng)點(diǎn)擊事件觸發(fā)時(shí),執(zhí)行點(diǎn)擊回調(diào)函數(shù),此時(shí)先創(chuàng)建執(zhí)行上下文,會(huì)拷貝作用域鏈到執(zhí)行上下文中。

  • 如果未在輸入框內(nèi)輸入字符,此時(shí)點(diǎn)擊拿到的v還是原來(lái)那個(gè)v
  • 如果在輸入框內(nèi)輸入了字符,此時(shí)調(diào)用了setV修改了state,頁(yè)面觸發(fā)render,組件內(nèi)部代碼會(huì)重新執(zhí)行一遍,重新聲明了一個(gè)v,v就不再是原來(lái)那個(gè)v,這里點(diǎn)擊事件里作用域中的v還是舊的v,這是兩個(gè)不同的v

產(chǎn)生場(chǎng)景

  • 事件綁定。比如示例代碼中,在頁(yè)面最初渲染完成后只綁定一次事件的情況,比如使用echarts,在useEffect中獲取echarts的實(shí)例并綁定事件
  • 定時(shí)器。頁(yè)面加載后注冊(cè)一個(gè)定時(shí)器,定時(shí)器內(nèi)的函數(shù)也會(huì)產(chǎn)生如此的閉包問(wèn)題。

解決辦法

針對(duì)這個(gè)閉包問(wèn)題下面大致給出5種解決辦法

1. 以賦值方式直接修改v,并將修改v的方法用useCallback包裹起來(lái)

將修改v的方法用useCallback包裹起來(lái),被useCallback包裹的函數(shù)將被緩存,由于依賴項(xiàng)的數(shù)組為空,所以這里直接賦值的方式修改的v是舊的v,此種方法不推薦,因?yàn)閟etState才是官方推薦的修改state的方式,這里仍然使用setV只是為了觸發(fā)rerender

// v 的聲明 由 const 改為 var,方便直接修改
var [v, setV] = useState('');

const inputHandle = useCallback(e => {
    let { value } = e.target
    v = value
    setV(value)
}, [])

2. 給useEffect的依賴項(xiàng)加上v

這也許是大多數(shù)人首先想到的辦法,既然v是舊的,那么每次v更新的時(shí)候,重新注冊(cè)一次事件不就行了,但是這樣的會(huì)導(dǎo)致每次v更新都得重新注冊(cè),理論應(yīng)該只需要注冊(cè)一次的事件變成了多次。

3. 避免v被重新聲明

以let或var的方式聲明某個(gè)變量代替v,直接修改這個(gè)變量,而不是要setState相關(guān)函數(shù)觸發(fā)render,這樣就不會(huì)被重新聲明,點(diǎn)擊的回調(diào)函數(shù)里就能拿到“最新”的值,但這個(gè)方法更不推薦,就此示例來(lái)說(shuō),input組件由于沒(méi)有rerender而至始至終都是顯示空值,不符合操作預(yù)期。

4. 使用useRef代替useState

const btn = useRef();
const vRef = useRef('');
const [v, setV] = useStat('');

useEffect(() => {
    let clickHandle = () => {
        console.log('v:', vRef.current);
    }
    btn.current.addEventListener('click', clickHandle)
    
    return () => {
        btn.removeEventListener('click', clickHandle)
    }
}, []);

const inputHandle = e => {
    let { value } = e.target
    vRef.current = value
    setV(value)
}

return (
        <>
            <input value={v} onChange={inputHandle} />
            <button ref={btn} >測(cè)試</button>
        </>
    )

useRef的方案之所以有效,是因?yàn)槊看蝘nput的change修改的是vRef這個(gè)對(duì)象的current屬性,而vRef始終是那個(gè)vRef,即使rerender,由于vRef是對(duì)象,所以變量存儲(chǔ)在棧內(nèi)存中的值是該對(duì)象在堆內(nèi)存中的地址,只是一個(gè)引用,只修改對(duì)象的某個(gè)屬性,該引用并不會(huì)改變。所以點(diǎn)擊事件中的作用域鏈?zhǔn)冀K訪問(wèn)的都是同一個(gè)vRef

5. 將v換成對(duì)象類型

其實(shí)和使用useRef一樣,只要是對(duì)象,僅修改某個(gè)屬性也不會(huì)改變?cè)搒tate所指向的地址。

代碼地址

點(diǎn)這里看測(cè)試代碼

到此這篇關(guān)于淺談react useEffect閉包的坑的文章就介紹到這了,更多相關(guān)react useEffect閉包內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • React函數(shù)組件傳參的實(shí)現(xiàn)

    React函數(shù)組件傳參的實(shí)現(xiàn)

    React函數(shù)組件通過(guò)接受props實(shí)現(xiàn)組件間的數(shù)據(jù)傳遞,通過(guò)組件標(biāo)簽的屬性向子組件傳遞數(shù)據(jù),并在子組件中通過(guò)參數(shù)接收,還可以使用ES6的解構(gòu)賦值,函數(shù)也能作為props傳遞,以實(shí)現(xiàn)父子組件間的交互和通信,下面就來(lái)具體了解一下
    2024-09-09
  • React-Native之定時(shí)器Timer的實(shí)現(xiàn)代碼

    React-Native之定時(shí)器Timer的實(shí)現(xiàn)代碼

    本篇文章主要介紹了React-Native之定時(shí)器Timer的實(shí)現(xiàn)代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-10-10
  • ReactHook使用useState更新變量后,如何拿到變量更新后的值

    ReactHook使用useState更新變量后,如何拿到變量更新后的值

    這篇文章主要介紹了ReactHook使用useState更新變量后,如何拿到變量更新后的值問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • React特征學(xué)習(xí)之Form格式示例詳解

    React特征學(xué)習(xí)之Form格式示例詳解

    這篇文章主要為大家介紹了React特征學(xué)習(xí)之Form格式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • react實(shí)現(xiàn)原生下拉刷新

    react實(shí)現(xiàn)原生下拉刷新

    這篇文章主要為大家詳細(xì)介紹了react實(shí)現(xiàn)原生下拉刷新,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • React.js組件實(shí)現(xiàn)拖拽排序組件功能過(guò)程解析

    React.js組件實(shí)現(xiàn)拖拽排序組件功能過(guò)程解析

    這篇文章主要介紹了React.js組件實(shí)現(xiàn)拖拽排序組件功能過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • React根據(jù)當(dāng)前頁(yè)面路由進(jìn)行自動(dòng)高亮示例代碼

    React根據(jù)當(dāng)前頁(yè)面路由進(jìn)行自動(dòng)高亮示例代碼

    要根據(jù)當(dāng)前頁(yè)面路由自動(dòng)高亮頂部菜單項(xiàng),可以使用 React Router 的 useLocation 鉤子來(lái)獲取當(dāng)前路徑,并根據(jù)路徑動(dòng)態(tài)設(shè)置菜單項(xiàng)的高亮效果,本文給大家介紹了一個(gè)完整的示例,展示如何根據(jù)當(dāng)前頁(yè)面路由自動(dòng)高亮頂部菜單項(xiàng),需要的朋友可以參考下
    2024-07-07
  • 深入淺析React中diff算法

    深入淺析React中diff算法

    React 最為核心的就是 Virtual DOM 和 Diff 算法,diff算法的基礎(chǔ)是Virtual DOM,接下來(lái)通過(guò)本文給大家介紹React中diff算法的相關(guān)知識(shí),對(duì)React中diff算法感興趣的朋友跟隨小編一起學(xué)習(xí)下吧
    2021-05-05
  • 簡(jiǎn)單分析React中的EffectList

    簡(jiǎn)單分析React中的EffectList

    這篇文章主要簡(jiǎn)單分析了React中的EffectList,幫助大家更好的理解和學(xué)習(xí)使用React進(jìn)行前端開(kāi)發(fā),感興趣的朋友可以了解下
    2021-04-04
  • React-router4路由監(jiān)聽(tīng)的實(shí)現(xiàn)

    React-router4路由監(jiān)聽(tīng)的實(shí)現(xiàn)

    這篇文章主要介紹了React-router4路由監(jiān)聽(tīng)的實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08

最新評(píng)論

临朐县| 四子王旗| 巩义市| 鞍山市| 夏津县| 韶山市| 满洲里市| 天津市| 双鸭山市| 惠州市| 钦州市| 青海省| 崇文区| 桦甸市| 温宿县| 竹山县| 南开区| 云浮市| 阳原县| 琼结县| 鄂尔多斯市| 天柱县| 当涂县| 宜良县| 张家口市| 安化县| 甘南县| 家居| 仁怀市| 金平| 彭水| 江门市| 稷山县| 山东省| 巍山| 靖宇县| 兰溪市| 合水县| 顺平县| 开原市| 丰台区|