亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

react中useEffect閉包的示例分析

發布時間:2021-06-09 09:48:33 來源:億速云 閱讀:153 作者:小新 欄目:開發技術

這篇文章主要介紹react中useEffect閉包的示例分析,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

問題代碼

看一段因為useEffect導致的閉包問題代碼

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的依賴項數組為空,所以在頁面渲染完成之后,內部代碼只會執行一次,頁面銷毀再執行一次。此時在輸入框中輸入任意字符,再點擊測試按鈕,得到的輸出為空,之后無論如何輸入任何字符,再點擊測試按鈕時,輸出的結果仍為空。

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

產生原因

函數的作用域在函數定義的時候就決定了

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

react中useEffect閉包的示例分析

能訪問到的自由變量v此時還是空值。當點擊事件觸發時,執行點擊回調函數,此時先創建執行上下文,會拷貝作用域鏈到執行上下文中。

  • 如果未在輸入框內輸入字符,此時點擊拿到的v還是原來那個v

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

產生場景

  • 事件綁定。比如示例代碼中,在頁面最初渲染完成后只綁定一次事件的情況,比如使用echarts,在useEffect中獲取echarts的實例并綁定事件

  • 定時器。頁面加載后注冊一個定時器,定時器內的函數也會產生如此的閉包問題。

解決辦法

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

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

將修改v的方法用useCallback包裹起來,被useCallback包裹的函數將被緩存,由于依賴項的數組為空,所以這里直接賦值的方式修改的v是舊的v,此種方法不推薦,因為setState才是官方推薦的修改state的方式,這里仍然使用setV只是為了觸發rerender

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

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

2. 給useEffect的依賴項加上v

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

3. 避免v被重新聲明

以let或var的方式聲明某個變量代替v,直接修改這個變量,而不是要setState相關函數觸發render,這樣就不會被重新聲明,點擊的回調函數里就能拿到“最新”的值,但這個方法更不推薦,就此示例來說,input組件由于沒有rerender而至始至終都是顯示空值,不符合操作預期。

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是對象,所以變量存儲在棧內存中的值是該對象在堆內存中的地址,只是一個引用,只修改對象的某個屬性,該引用并不會改變。所以點擊事件中的作用域鏈始終訪問的都是同一個vRef

react中useEffect閉包的示例分析

5. 將v換成對象類型

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

以上是“react中useEffect閉包的示例分析”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

格尔木市| 建昌县| 离岛区| 灵璧县| 张家界市| 江门市| 淮南市| 黄骅市| 上林县| 舟山市| 阳东县| 深水埗区| 盘山县| 义马市| 武定县| 达日县| 乌拉特后旗| 和田市| 祁东县| 遂宁市| 香格里拉县| 龙胜| 平泉县| 彭水| 资源县| 井冈山市| 上蔡县| 鸡东县| 交城县| 连山| 嘉黎县| 临沂市| 信阳市| 大庆市| 乡城县| 建宁县| 阿图什市| 成都市| 大洼县| 永州市| 伊金霍洛旗|