亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

淺談react useEffect閉包的坑

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

問題代碼

看一段因為useEffect導(dǎo)致的閉包問題代碼

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} >測試</button>
        </>
    )

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

為什么會這樣呢?其實就是閉包所造成的。

產(chǎn)生原因

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

給btn注冊點擊事件時,作用域如下:

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

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

產(chǎn)生場景

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

解決辦法

針對這個閉包問題下面大致給出5種解決辦法

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

將修改v的方法用useCallback包裹起來,被useCallback包裹的函數(shù)將被緩存,由于依賴項的數(shù)組為空,所以這里直接賦值的方式修改的v是舊的v,此種方法不推薦,因為setState才是官方推薦的修改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的依賴項加上v

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

3. 避免v被重新聲明

以let或var的方式聲明某個變量代替v,直接修改這個變量,而不是要setState相關(guān)函數(shù)觸發(fā)render,這樣就不會被重新聲明,點擊的回調(diào)函數(shù)里就能拿到“最新”的值,但這個方法更不推薦,就此示例來說,input組件由于沒有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} >測試</button>
        </>
    )

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

5. 將v換成對象類型

其實和使用useRef一樣,只要是對象,僅修改某個屬性也不會改變該state所指向的地址。

代碼地址

這里看測試代碼

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

相關(guān)文章

  • React三大屬性之Refs的使用詳解

    React三大屬性之Refs的使用詳解

    這篇文章主要介紹了React三大屬性之Refs的使用詳解,幫助大家更好的理解和學(xué)習(xí)使用React,感興趣的朋友可以了解下
    2021-04-04
  • VSCode配置react開發(fā)環(huán)境的步驟

    VSCode配置react開發(fā)環(huán)境的步驟

    本篇文章主要介紹了VSCode配置react開發(fā)環(huán)境的步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • 使用react context 實現(xiàn)vue插槽slot功能

    使用react context 實現(xiàn)vue插槽slot功能

    這篇文章主要介紹了使用react context 實現(xiàn)vue插槽slot功能,文中給大家介紹了vue的slot的實現(xiàn)方法,需要的朋友可以參考下
    2019-07-07
  • 解決React報錯Property value does not exist on type HTMLElement

    解決React報錯Property value does not exist&n

    這篇文章主要為大家介紹了React報錯Property value does not exist on type HTMLElement解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • 詳解如何在React單頁面應(yīng)用中捕獲錯誤

    詳解如何在React單頁面應(yīng)用中捕獲錯誤

    在當(dāng)前的Web開發(fā)中,使用React構(gòu)建單頁面應(yīng)用(SPA)已經(jīng)成為一種常見的做法,然而,當(dāng)應(yīng)用程序遇到錯誤時,有可能會導(dǎo)致整個頁面崩潰,給用戶帶來不好的體驗,本文將介紹如何在React單頁面應(yīng)用中捕獲錯誤,以防止整個頁面的崩潰,需要的朋友可以參考下
    2023-09-09
  • react搭建環(huán)境時執(zhí)行npm start報錯start: 'react-scripts start'的解決

    react搭建環(huán)境時執(zhí)行npm start報錯start: 'react-scripts&

    這篇文章主要介紹了react搭建環(huán)境時執(zhí)行npm start報錯start: 'react-scripts start'的解決方案,具有很好的參考價值,希望杜對大家有所幫助,
    2023-10-10
  • 詳解React項目中碰到的IE問題

    詳解React項目中碰到的IE問題

    這篇文章主要介紹了React項目中碰到的IE問題,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • 一文詳解如何React中實現(xiàn)插槽

    一文詳解如何React中實現(xiàn)插槽

    這篇文章主要為大家詳細介紹了如何在React中實現(xiàn)插槽,文中的示例代碼講解詳細,對我們的學(xué)習(xí)或工作具有一定的借鑒價值,需要的可以了解一下
    2023-03-03
  • react使用css module無法重寫bootstrap樣式問題及解決

    react使用css module無法重寫bootstrap樣式問題及解決

    這篇文章主要介紹了react使用css module無法重寫bootstrap樣式問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • react用Redux中央倉庫實現(xiàn)一個todolist

    react用Redux中央倉庫實現(xiàn)一個todolist

    這篇文章主要為大家詳細介紹了react用Redux中央倉庫實現(xiàn)一個todolist,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-09-09

最新評論