網(wǎng)站首頁 編程語言 正文
總覽
產(chǎn)生"Too many re-renders. React limits the number of renders to prevent an infinite loop"錯誤有多方面的原因:
- 在一個組件的渲染方法中調(diào)用一個設置狀態(tài)的函數(shù)。
- 立即調(diào)用一個事件處理器,而不是傳遞一個函數(shù)。
- 有一個無限設置與重渲染的
useEffect
鉤子。
這里有個示例來展示錯誤是如何發(fā)生的:
import {useState} from 'react'; export default function App() { const [counter, setCounter] = useState(0); // ?? Too many re-renders. React limits the number // of renders to prevent an infinite loop. return ( <div> <button onClick={setCounter(counter + 1)}>Increment</button> <h1>Count: {counter}</h1> </div> ); }
上述代碼問題在于,我們在onClick
事件處理器中立即調(diào)用了setCounter
函數(shù)。
該函數(shù)是在頁面加載時立即被調(diào)用,而不是事件觸發(fā)后調(diào)用。
傳遞函數(shù)
為了解決該錯誤,為onClick
事件處理器傳遞函數(shù),而不是傳遞調(diào)用函數(shù)的結(jié)果。
import {useState} from 'react'; export default function App() { const [counter, setCounter] = useState(0); return ( <div> <button onClick={() => setCounter(counter + 1)}>Increment</button> <h1>Count: {counter}</h1> </div> ); }
現(xiàn)在,我們?yōu)槭录幚砥鱾鬟f了函數(shù),而不是當頁面加載時調(diào)用setCounter
方法。
如果該方法在頁面加載時被調(diào)用,就會觸發(fā)一個setState
動作,組件就會無限重新渲染。
如果我們試圖立即設置一個組件的狀態(tài),而不使用一個條件或事件處理器,也會發(fā)生這個錯誤。
import {useState} from 'react'; export default function App() { const [counter, setCounter] = useState(0); // ?? Too many re-renders. React limits the number // of renders to prevent an infinite loop. setCounter(counter + 1); return ( <div> <h1>Count: {counter}</h1> </div> ); }
問題在于,setCounter
函數(shù)在組件渲染時被調(diào)用、更新狀態(tài),并導致重新渲染,而且是無限重新渲染。
你可以通過向useState()
鉤子傳遞一個初始值或一個函數(shù)來初始化狀態(tài),從而解決這個錯誤。
import {useState} from 'react'; export default function App() { const [counter, setCounter] = useState(() => 100 + 100); return ( <div> <h1>Count: {counter}</h1> </div> ); }
我們向useState
方法傳遞了一個函數(shù)。這個函數(shù)只會在組件第一次渲染時被調(diào)用,并且會計算出初始狀態(tài)。你也可以直接向useState
方法傳遞一個初始值。
另外,你也可以像前面的例子那樣使用一個條件或事件處理器。
import {useState} from 'react'; export default function App() { const [counter, setCounter] = useState(0); // ?? your condition here if (Math.random() > 0.5) { setCounter(counter + 1); } return ( <div> <h1>Count: {counter}</h1> </div> ); }
如果你像上面的例子那樣使用一個條件,請確保該條件不總是返回一個真值,因為這將導致無限的重新渲染循環(huán)。
"Too many re-renders. React limits the number of renders to prevent an infinite loop"錯誤也會在使用useEffect
方法時發(fā)生,該方法的依賴會導致無限重新渲染。
import {useEffect, useState} from 'react'; export default function App() { const [counter, setCounter] = useState(0); useEffect(() => { // ?? Too many re-renders. React limits the number // of renders to prevent an infinite loop. setCounter(counter + 1); }); // ?? forgot to pass dependency array return ( <div> <h1>Count: {counter}</h1> </div> ); }
上述代碼問題在于,我們沒有為useEffect
鉤子傳遞依賴數(shù)組。
這意味著該鉤子會在每次渲染時運行,它會更新組件的狀態(tài),然后無限重新運行。
傳遞依賴
解決該錯誤的一種辦法是,為useEffect
提供空數(shù)組作為第二個參數(shù)。
import {useEffect, useState} from 'react'; export default function App() { const [counter, setCounter] = useState(0); useEffect(() => { setCounter(counter + 1); }, []); // ?? empty dependencies array return ( <div> <h1>Count: {counter}</h1> </div> ); }
如果你為
useEffect
方法傳遞空數(shù)組依賴作為第二個參數(shù),該方法只在組件的初始渲染時運行。
該代碼將計數(shù)器遞增到1
,并且不再運行,無論App
組件是否被重新渲染。
如果你必須指定一個依賴來無限地重新渲染你的組件,試著尋找一個可以防止這種情況的條件。
import {useEffect, useState} from 'react'; export default function App() { const [counter, setCounter] = useState(0); useEffect(() => { // ?? some condition here if (Math.random() > 0.5) { setCounter(counter + 1); } }, [counter]); return ( <div> <h1>Count: {counter}</h1> </div> ); }
有可能是某些邏輯決定了狀態(tài)是否應該被更新,而狀態(tài)不應該在每次重新渲染時被設置。
確保你沒有使用一個在每次渲染時都不同的對象或數(shù)組作為useEffect
鉤子的依賴。
import {useEffect, useState} from 'react'; export default function App() { const [address, setAddress] = useState({country: '', city: ''}); const obj = {country: 'Chile', city: 'Santiago'}; useEffect(() => { // ?? Too many re-renders. React limits the number // of renders to prevent an infinite loop. setAddress(obj); console.log('useEffect called'); }, [obj]); return ( <div> <h1>Country: {address.country}</h1> <h1>City: {address.city}</h1> </div> ); }
問題在于,在JavaScript中,對象是通過引用進行比較的。obj
變量存儲了一個具有相同鍵值對的對象,但每次渲染時的引用不同(在內(nèi)存中的位置不同)。
移入依賴
解決該錯誤的一種辦法是,把這個對象移到useEffect
鉤子里面,這樣我們就可以把它從依賴數(shù)組中移除。
import {useEffect, useState} from 'react'; export default function App() { const [address, setAddress] = useState({country: '', city: ''}); useEffect(() => { // ?? move object inside of useEffect // and remove it from dependencies array const obj = {country: 'Chile', city: 'Santiago'}; setAddress(obj); console.log('useEffect called'); }, []); return ( <div> <h1>Country: {address.country}</h1> <h1>City: {address.city}</h1> </div> ); }
傳遞對象屬性
另一個解決方案是將對象的屬性傳遞給依賴數(shù)組。
import {useEffect, useState} from 'react'; export default function App() { const [address, setAddress] = useState({country: '', city: ''}); const obj = {country: 'Chile', city: 'Santiago'}; useEffect(() => { setAddress({country: obj.country, city: obj.city}); console.log('useEffect called'); // ?? object properties instead of the object itself }, [obj.country, obj.city]); return ( <div> <h1>Country: {address.country}</h1> <h1>City: {address.city}</h1> </div> ); }
現(xiàn)在React不是在測試一個對象是否發(fā)生了變化,而是在測試obj.country
和obj.city
字符串在渲染之間是否發(fā)生了變化。
記憶值
另外,我們可以使用useMemo
鉤子來獲得一個在不同渲染之間不會改變的記憶值。
import {useEffect, useMemo, useState} from 'react'; export default function App() { const [address, setAddress] = useState({country: '', city: ''}); // ?? get memoized value const obj = useMemo(() => { return {country: 'Chile', city: 'Santiago'}; }, []); useEffect(() => { setAddress(obj); console.log('useEffect called'); }, [obj]); return ( <div> <h1>Country: {address.country}</h1> <h1>City: {address.city}</h1> </div> ); }
我們將對象的初始化包裹在useMemo
鉤子里面,以獲得一個不會在渲染之間改變的記憶值。
我們傳遞給useMemo
鉤子的第二個參數(shù)是一個依賴數(shù)組,它決定了我們傳遞給useMemo
的回調(diào)函數(shù)何時被重新運行。
需要注意的是,數(shù)組在JavaScript中也是通過引用進行比較的。所以一個具有相同值的數(shù)組也可能導致你的useEffect
鉤子被無限次觸發(fā)。
import {useEffect, useMemo, useState} from 'react'; export default function App() { const [nums, setNums] = useState([1, 2, 3]); const arr = [4, 5, 6]; useEffect(() => { // ?? Too many re-renders. React limits the number // of renders to prevent an infinite loop. setNums(arr); console.log('useEffect called'); }, [arr]); return <div>{nums[0]}</div>; }
數(shù)組在重新渲染之間存儲相同的值,但指向內(nèi)存中的不同位置,并且在每次組件重新渲染時有不同的引用。
在處理數(shù)組時,我們用于對象的方法同樣有效。例如,我們可以使用useMemo
鉤子來獲得一個在渲染之間不會改變的記憶值。
import {useEffect, useMemo, useState} from 'react'; export default function App() { const [nums, setNums] = useState([1, 2, 3]); const arr = useMemo(() => { return [4, 5, 6]; }, []); useEffect(() => { setNums(arr); console.log('useEffect called'); }, [arr]); return <div>{nums[0]}</div>; }
我們將數(shù)組的初始化包裹在useMemo
鉤子里面,以獲得一個不會在不同渲染之間改變的記憶值。
原文鏈接:https://juejin.cn/post/7176637831199064123
相關推薦
- 2022-09-09 python定義函數(shù)如何判斷年份是否為閏年_python
- 2023-04-12 在redis中防止消息丟失的機制_Redis
- 2022-12-07 C語言如何求整數(shù)的位數(shù)及各位數(shù)字之和_C 語言
- 2022-05-09 python?itertools包內(nèi)置無限迭代器_python
- 2022-04-01 win10應用程序開機自動啟動設置
- 2022-05-10 torch.cuda.is_available()返回false最終解決方案
- 2023-03-26 C#?cefSharep控件的使用詳情_C#教程
- 2023-02-14 OKhttp攔截器實現(xiàn)實踐環(huán)節(jié)源碼解析_Android
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學習環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支