如何解決React useEffect鉤子帶來(lái)的無(wú)限循環(huán)問(wèn)題
React的useEffect Hook
可以讓用戶處理應(yīng)用程序的副作用
。例如:
從網(wǎng)絡(luò)獲取數(shù)據(jù)
:應(yīng)用程序通常在第一次加載時(shí)獲取并填充數(shù)據(jù)。這可以通過(guò)useEffect
函數(shù)實(shí)現(xiàn)操作UI
:應(yīng)用程序應(yīng)該響應(yīng)按鈕點(diǎn)擊事件(例如,打開(kāi)一個(gè)菜單)設(shè)置或結(jié)束計(jì)時(shí)器
:如果某個(gè)變量達(dá)到預(yù)定義值,則內(nèi)置計(jì)時(shí)器應(yīng)自行停止或啟動(dòng)
盡管useEffect Hook在React生態(tài)系統(tǒng)中很常見(jiàn),但它需要時(shí)間來(lái)掌握。因此,許多新手開(kāi)發(fā)人員在配置他們的useEffect函數(shù)時(shí),會(huì)導(dǎo)致無(wú)限循環(huán)問(wèn)題。在本文中,您將了解不同場(chǎng)景下帶來(lái)的無(wú)限循環(huán)問(wèn)題以及如何解決它們。
這是我們今天要學(xué)習(xí)的內(nèi)容:
是什么導(dǎo)致無(wú)限循環(huán)以及如何解決它們:
- 在依賴項(xiàng)數(shù)組中不傳遞依賴項(xiàng)
- 使用函數(shù)作為依賴項(xiàng)
- 使用數(shù)組作為依賴項(xiàng)
- 使用對(duì)象作為依賴項(xiàng)
- 傳遞不正確的依賴項(xiàng)
什么導(dǎo)致的無(wú)限循環(huán)以及如何解決它們
在依賴項(xiàng)數(shù)組中不傳遞依賴項(xiàng)
如果您的useEffect函數(shù)不包含任何依賴項(xiàng),則會(huì)出現(xiàn)一個(gè)無(wú)限循環(huán)。
例如,看看下面的代碼:
function App() { const [count, setCount] = useState(0); //初始化值 useEffect(() => { setCount((count) => count + 1); }); //無(wú)依賴項(xiàng) return ( <div className="App"> <p> value of count: {count} </p> </div> ); }
如果沒(méi)有依賴關(guān)系,則默認(rèn)在每個(gè)更新周期上觸發(fā)useEffect。因此,這里的應(yīng)用程序?qū)⒃?strong>每次渲染時(shí)執(zhí)行setCount函數(shù)。因此,這會(huì)導(dǎo)致一個(gè)無(wú)限循環(huán):
是什么導(dǎo)致了這個(gè)問(wèn)題?讓我們一步一步來(lái)分析這個(gè)問(wèn)題:
- 在第一次渲染時(shí),React會(huì)檢查
count
的值。在這里,由于count為0,程序執(zhí)行useEffect函數(shù) - 稍后,useEffect調(diào)用setCount方法并更新count的值
- 之后,React重新呈現(xiàn)UI以顯示count的更新值
- 此外,由于
useEffect在每個(gè)呈現(xiàn)周期中運(yùn)行
,它將重新調(diào)用setCount函數(shù)
- 由于上述步驟發(fā)生在每一個(gè)渲染,這導(dǎo)致你的應(yīng)用程序崩潰
如何解決這個(gè)問(wèn)題
為了緩解這個(gè)問(wèn)題,我們必須使用依賴數(shù)組,告訴React只有在特定值更新時(shí)才調(diào)用useEffect。
下一步,像這樣附加一個(gè)空白數(shù)組作為依賴項(xiàng):
useEffect(() => { setCount((count) => count + 1); }, []); //empty array as second argument.
這告訴React在第一次裝載時(shí)執(zhí)行setCount
函數(shù)。
使用函數(shù)作為依賴項(xiàng)
如果你把一個(gè)方法傳入你的useEffect
依賴數(shù)組,React會(huì)拋出一個(gè)錯(cuò)誤,表明你有一個(gè)無(wú)限循環(huán):
function App() { const [count, setCount] = useState(0); function logResult() { return 2 + 2; } useEffect(() => { setCount((count) => count + 1); }, [logResult]); // 函數(shù)作為依賴項(xiàng) return ( <div className="App"> <p> value of count: {count} </p> </div> ); }
在這段代碼中,我們將logResult
方法傳遞給useEffect
數(shù)組。理論上,React只需要在第一次渲染時(shí)增加count
的值。
是什么導(dǎo)致了這個(gè)問(wèn)題?
- 要記住的一件事是,useEffect使用了一個(gè)叫做淺比較的概念。它這樣做是為了驗(yàn)證依賴項(xiàng)是否已經(jīng)更新
- 這里的問(wèn)題是,在每次呈現(xiàn)期間,React都會(huì)重新定義logResult的引用
- 因此,這將在每個(gè)循環(huán)中重新觸發(fā)useEffect函數(shù)
- 因此,React會(huì)調(diào)用setCount鉤子,直到應(yīng)用程序遇到更新深度錯(cuò)誤。這會(huì)給程序帶來(lái)錯(cuò)誤和不穩(wěn)定性
如何解決這個(gè)問(wèn)題
一個(gè)解決方案是使用useCallback
鉤子。這允許開(kāi)發(fā)人員記住他們的函數(shù),從而確保引用值保持不變。由于這個(gè)參考值是穩(wěn)定的,React不應(yīng)該無(wú)限地重新渲染UI:
const logResult = useCallback(() => { return 2 + 2; }, []); // logResult是緩存的 useEffect(()=> { setCount((count)=> count+1); },[logResult]); //沒(méi)有無(wú)限循環(huán)錯(cuò)誤,因?yàn)閘ogResult引用保持不變。
結(jié)果:
使用數(shù)組作為依賴項(xiàng)
將數(shù)組變量傳遞給依賴項(xiàng)也會(huì)運(yùn)行一個(gè)無(wú)限循環(huán)。考慮下面的代碼示例:
const [count, setCount] = useState(0); //初始值為0。 const myArray = ["one", "two", "three"]; useEffect(() => { setCount((count) => count + 1); // 和前面一樣,增加Count的值 }, [myArray]); // 將數(shù)組變量傳遞給依賴項(xiàng)
在這個(gè)塊中,我們將myArray變量傳入依賴參數(shù)。
是什么導(dǎo)致了這個(gè)問(wèn)題?
既然myArray的值在整個(gè)程序中都沒(méi)有改變,為什么我們的代碼會(huì)多次觸發(fā)useEffect ?
- 在這里,回想一下React使用淺比較來(lái)檢查依賴項(xiàng)的引用是否發(fā)生了變化。
- 由于對(duì)myArray的引用在每次渲染時(shí)都在變化,useEffect將觸發(fā)setCount回調(diào)
- 因此,由于myArray的引用值不穩(wěn)定,React將在每個(gè)渲染周期中調(diào)用useEffect。最終,這會(huì)導(dǎo)致應(yīng)用程序崩潰
如何解決這個(gè)問(wèn)題
為了解決這個(gè)問(wèn)題,我們可以使用useRefHook。這將返回一個(gè)可變對(duì)象,確保引用不會(huì)改變:
const [count, setCount] = useState(0); //提取“current”屬性并給它賦值 const { current: myArray } = useRef(["one", "two", "three"]); useEffect(() => { setCount((count) => count + 1); }, [myArray]); //依賴值是穩(wěn)定的,所以沒(méi)有無(wú)限循環(huán)
將對(duì)象作為依賴項(xiàng)傳遞
在useEffect依賴數(shù)組中使用對(duì)象也會(huì)導(dǎo)致無(wú)限循環(huán)問(wèn)題。
考慮下面的代碼:
const [count, setCount] = useState(0); const person = { name: "Rue", age: 17 }; //創(chuàng)建一個(gè)對(duì)象 useEffect(() => { // 每次增加count的值 // person的值發(fā)生了變化 setCount((count) => count + 1); }, [person]); // 依賴項(xiàng)數(shù)組包含一個(gè)對(duì)象作為參數(shù) return ( <div className="App"> <p> Value of {count} </p> </div> );
控制臺(tái)的結(jié)果表明程序是無(wú)限循環(huán)的:
是什么導(dǎo)致了這個(gè)問(wèn)題?
- 和之前一樣,React使用淺比較來(lái)檢查person的參考值是否發(fā)生了變化
- 因?yàn)?strong>person對(duì)象的引用值在每次渲染時(shí)都會(huì)改變,所以React會(huì)重新運(yùn)行useEffect
- 因此,在每個(gè)更新周期中調(diào)用setCount。這意味著我們現(xiàn)在有了一個(gè)無(wú)限循環(huán)
如何解決這個(gè)問(wèn)題
那么我們?nèi)绾谓鉀Q這個(gè)問(wèn)題呢?
這就是usemmo
的用武之地。**當(dāng)依賴關(guān)系發(fā)生變化時(shí),這個(gè)鉤子會(huì)計(jì)算一個(gè)記憶的值。**除此之外,因?yàn)槲覀冇涀×艘粋€(gè)變量,這確保了狀態(tài)的引用值在每次渲染期間不會(huì)改變:
// 使用usemo創(chuàng)建一個(gè)對(duì)象 const person = useMemo( () => ({ name: "Rue", age: 17 }), [] //沒(méi)有依賴關(guān)系,所以值不會(huì)改變 ); useEffect(() => { setCount((count) => count + 1); }, [person]);
傳遞不正確的依賴項(xiàng)
如果將錯(cuò)誤的變量傳遞給useEffect函數(shù),React將拋出一個(gè)錯(cuò)誤。
下面是一個(gè)簡(jiǎn)單的例子:
const [count, setCount] = useState(0); useEffect(() => { setCount((count) => count + 1); }, [count]); //注意,我們將count傳遞給了這個(gè)數(shù)組。 return ( <div className="App"> <button onClick={() => setCount((count) => count + 1)}>+</button> <p> Value of count{count} </p> </div> );
是什么導(dǎo)致了這個(gè)問(wèn)題?
- 在上面的代碼中,我們告訴在useEffect方法中更新count的值
- 此外,注意我們也將count Hook傳遞給了它的依賴數(shù)組
- 這意味著每次count值更新時(shí),React都會(huì)調(diào)用useEffect
- 因此,useEffect鉤子調(diào)用setCount,從而再次更新count
- 因此,React現(xiàn)在在一個(gè)無(wú)限循環(huán)中運(yùn)行我們的函數(shù)
如何解決這個(gè)問(wèn)題
要擺脫無(wú)限循環(huán),只需像這樣使用一個(gè)空的依賴數(shù)組:
const [count, setCount] = useState(0); // 只有在組件首次掛載時(shí)才更新'count'的值 useEffect(() => { setCount((count) => count + 1); }, []);
這將告訴React在第一次渲染時(shí)運(yùn)行useEffect。
結(jié)尾
盡管React Hooks是一個(gè)簡(jiǎn)單的概念,但是在將它們整合到項(xiàng)目中時(shí),仍然需要記住許多規(guī)則。這將確保您的應(yīng)用程序保持穩(wěn)定,優(yōu)化,并在生產(chǎn)過(guò)程中不拋出錯(cuò)誤。
此外,最近發(fā)布的Create React App CLI
也會(huì)在運(yùn)行時(shí)檢測(cè)和報(bào)告無(wú)限循環(huán)錯(cuò)誤。這有助于開(kāi)發(fā)人員在這些問(wèn)題出現(xiàn)在生產(chǎn)服務(wù)器上之前發(fā)現(xiàn)并解決這些問(wèn)題。
到此這篇關(guān)于如何解決React useEffect鉤子帶來(lái)的無(wú)限循環(huán)問(wèn)題的文章就介紹到這了,更多相關(guān)React useEffect鉤子無(wú)限循環(huán)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用React+ts實(shí)現(xiàn)無(wú)縫滾動(dòng)的走馬燈詳細(xì)過(guò)程
這篇文章主要給大家介紹了關(guān)于使用React+ts實(shí)現(xiàn)無(wú)縫滾動(dòng)的走馬燈詳細(xì)過(guò)程,文中給出了詳細(xì)的代碼示例以及圖文教程,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-08-08深入了解響應(yīng)式React Native Echarts組件
近年來(lái),隨著移動(dòng)端對(duì)數(shù)據(jù)可視化的要求越來(lái)越高,通過(guò) WebView 在移動(dòng)端使用 Echarts 這樣功能強(qiáng)大的前端數(shù)據(jù)可視化庫(kù),是解決問(wèn)題的好辦法。下面就和小編來(lái)一起學(xué)習(xí)一下吧2019-05-05React Hook - 自定義Hook的基本使用和案例講解
自定義Hook本質(zhì)上只是一種函數(shù)代碼邏輯的抽取,嚴(yán)格意義上來(lái)說(shuō),它本身并不算React的特性,這篇文章主要介紹了React類(lèi)組件和函數(shù)組件對(duì)比-Hooks的介紹及初體驗(yàn),需要的朋友可以參考下2022-11-11React特征學(xué)習(xí)Form數(shù)據(jù)管理示例詳解
這篇文章主要為大家介紹了React特征學(xué)習(xí)Form數(shù)據(jù)管理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09詳解在React項(xiàng)目中安裝并使用Less(用法總結(jié))
這篇文章主要介紹了詳解在React項(xiàng)目中安裝并使用Less(用法總結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03React?Hooks useReducer?逃避deps組件渲染次數(shù)增加陷阱
這篇文章主要介紹了React?Hooks?之?useReducer?逃避deps后增加組件渲染次數(shù)的陷阱詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09