آنچه در این مقاله میخوانید [پنهانسازی]
Infinite Loop در React معمولا زمانی اتفاق میافتد که useEffect مدام باعث تغییر State شود و هر تغییر دوباره کامپوننت را Render کند. این مشکل بیشتر به خاطر Dependency اشتباه، تغییر مداوم State یا استفاده نادرست از Object و Function داخل useEffect رخ میدهد. اگر دلیل اصلی Loop را پیدا نکنید، پروژه ممکن است کند شود، API چندین بار صدا زده شود یا حتی مرورگر Crash کند.
سرفصل های مقاله
- useEffect در React چه کاری انجام میدهد؟
- Infinite Loop در React چیست؟
- چرا useEffect باعث Infinite Loop میشود؟
- نداشتن Dependency Array
- تغییر State داخل useEffect
- استفاده اشتباه از Object و Array
- استفاده اشتباه از Function داخل Dependency
- روش حل مشکل Function Dependency
- صدا زدن API داخل Loop
- نشانههای Infinite Loop در React
- چگونه Infinite Loop را پیدا کنیم؟
- استفاده از Console.log
- استفاده از React DevTools
- بررسی Dependency Array
- روش اصولی حل Infinite Loop در React
- Dependency ها را درست مدیریت کنید
- از useMemo استفاده کنید
- از useCallback استفاده کنید
- State غیر ضروری نسازید
- اشتباهات رایج برنامه نویسان React
- قرار دادن State داخل Dependency بدون نیاز
- ساخت Object داخل JSX
- استفاده زیاد از Global State
- روش جلوگیری از Infinite Loop در React
- کامپوننتها را کوچک نگه دارید
- Effect های پروژه را ساده نگه دارید
- قبل از اضافه کردن Dependency فکر کنید
- از ESLint Plugin React Hooks استفاده کنید
- جمع بندی
useEffect در React چه کاری انجام میدهد؟
هوک useEffect برای اجرای Side Effect ها در React استفاده میشود.
مثلا:
- دریافت داده از API
- اجرای Timer
- مدیریت Event Listener
- تغییر Title صفحه
نمونه ساده:
useEffect(() => {
console.log("Component Mounted")
}, [])
در این مثال، Effect فقط یک بار بعد از Render اولیه اجرا می شود.
Infinite Loop در React چیست؟
Infinite Loop یعنی کامپوننت مدام Render شود و هیچ وقت متوقف نشود.
مثلا:
- State تغییر میکند
- Render جدید اتفاق میافتد
- useEffect دوباره اجرا میشود
- دوباره State تغییر میکند
و این چرخه تا بی نهایت ادامه پیدا میکند.
نتیجه معمولا:
- کند شدن شدید صفحه
- مصرف بالای RAM
- Crash شدن مرورگر
- درخواستهای تکراری API
است.
چرا useEffect باعث Infinite Loop میشود؟
دلایل مختلفی وجود دارد اما بعضی اشتباهات بسیار رایجتر هستند.
نداشتن Dependency Array
یکی از رایجترین دلایل Infinite Loop همین است.
مثلا:
useEffect(() => {
fetchData()
})
در این حالت useEffect بعد از هر Render اجرا میشود.
اگر داخل fetchData تغییر State داشته باشید، کامپوننت دوباره Render می شود و Loop شکل میگیرد.
روش درست:
useEffect(() => {
fetchData()
}, [])
حالا فقط یک بار اجرا میشود.
تغییر State داخل useEffect
این مورد خیلی رایج است:
useEffect(() => {
setCount(count + 1)
}, [count])
اینجا:
- count تغییر میکند
- useEffect دوباره اجرا میشود
- دوباره count تغییر میکند
و Loop بی نهایت ایجاد میشود.
استفاده اشتباه از Object و Array
بعضی وقتها Dependency ها در ظاهر ثابت هستند اما React آن ها را جدید در نظر میگیرد.
مثلا:
const user = {name: "Ali"}
useEffect(() => {
console.log(user)
}, [user])
در هر Render یک Object جدید ساخته میشود.
در نتیجه useEffect دوباره اجرا میشود.
استفاده اشتباه از Function داخل Dependency
مثلا:
const getData = () => {
console.log("fetch")
}
useEffect(() => {
getData()
}, [getData])
چون Function در هر Render دوباره ساخته میشود، Effect هم دوباره اجرا میشود.
روش حل مشکل Function Dependency
میتوانید از useCallback استفاده کنید:
const getData = useCallback(() => {
console.log("fetch")
}, [])
حالا React Function را ثابت نگه میدارد.
صدا زدن API داخل Loop
یکی از بدترین حالتها این است که Infinite Loop باعث Request های بی پایان شود.
مثلا:
useEffect(() => {
fetch('/api/data')
.then(res => res.json())
.then(data => setData(data))
}, [data])
اینجا:
- setData باعث تغییر data میشود
- useEffect دوباره اجرا میشود
- API دوباره صدا زده میشود
و سرور ممکن است کاملا تحت فشار قرار بگیرد.
نشانههای Infinite Loop در React
معمولا این مشکل با یکی از این نشانهها مشخص میشود:
- مرورگر کند میشود
- فن لپ تاپ شدید کار میکند
- API مدام Request میگیرد
- Console پر از Log تکراری میشود
- React Error نمایش داده میشود
مثلا:
Maximum update depth exceeded
این خطا یعنی کامپوننت بیش از حد Render شده است.
چگونه Infinite Loop را پیدا کنیم؟
استفاده از Console.log
سادهترین روش:
console.log("render")
اگر مدام تکرار شود یعنی Loop دارید.
استفاده از React DevTools
داخل Profiler میتوانید ببینید:
- چه چیزی Render شده
- چند بار Render شده
- دلیل Render چه بوده
این ابزار برای Debug خیلی مهم است.
بررسی Dependency Array
بیشتر Loop ها از همین قسمت شروع میشوند.
باید بررسی کنید:
- آیا Dependency واقعا لازم است؟
- آیا مقدار مدام تغییر میکند؟
- آیا Object یا Function جدید ساخته میشود؟
روش اصولی حل Infinite Loop در React
Dependency ها را درست مدیریت کنید
همیشه Dependency واقعی را قرار دهید.
مثلا:
useEffect(() => {
fetchUsers()
}, [])
این باعث میشود Effect فقط یک بار اجرا شود.
از useMemo استفاده کنید
برای Object یا Array:
const config = useMemo(() => {
return {theme: 'dark'}
}, [])
این کار از ساخت Object جدید جلوگیری میکند.
از useCallback استفاده کنید
برای Function ها:
const fetchData = useCallback(() => {
console.log("data")
}, [])
این روش جلوی Render اضافی را میگیرد.
State غیر ضروری نسازید
هر State جدید یعنی احتمال Render بیشتر.
گاهی داده اصلا نیاز به State ندارد.
اشتباهات رایج برنامه نویسان React
قرار دادن State داخل Dependency بدون نیاز
مثلا:
useEffect(() => {
loadData()
}, [data])
در حالی که data هیچ ارتباطی با Effect ندارد.
ساخت Object داخل JSX
مثلا:
<Component style={{color: 'red'}} />
در پروژه های بزرگ این کار باعث Render اضافی می شود.
استفاده زیاد از Global State
بعضی پروژهها همه چیز را داخل Redux یا Context ذخیره میکنند.
نتیجه:
- Render زیاد
- مصرف RAM بالا
- Performance ضعیف
روش جلوگیری از Infinite Loop در React
کامپوننتها را کوچک نگه دارید
کامپوننتهای بزرگ:
- Debug سختتری دارند
- Loop های پیچیدهتری ایجاد می کنند
Effect های پروژه را ساده نگه دارید
هر useEffect باید فقط یک وظیفه مشخص داشته باشد.
Effect های شلوغ معمولا مشکل ساز میشوند.
قبل از اضافه کردن Dependency فکر کنید
هر Dependency جدید میتواند باعث Render دوباره شود.
نباید بدون دلیل Dependency اضافه شود.
از ESLint Plugin React Hooks استفاده کنید
این ابزار خیلی از اشتباهات مربوط به useEffect را پیدا میکند.
نصب:
npm install eslint-plugin-react-hooks
جمع بندی
Infinite Loop در React معمولا به خاطر استفاده اشتباه از useEffect، تغییر مداوم State یا مدیریت نادرست Dependency ها اتفاق می افتد. بیشتر این مشکلات با استفاده درست از Dependency Array، useMemo و useCallback قابل حل هستند. مهمترین نکته این است که دقیقا بدانید چه چیزی باعث Render دوباره کامپوننت میشود تا بتوانید Loop را کنترل کنید.





