{
“@context”: “https://schema.org”,
“@type”: “TechArticle”,
“headline”: “رد فعل useEffect Infinite Loop: لماذا يحدث وكيفية إصلاحه بالضبط”,
“description”: “الدليل الكامل لتشخيص وإصلاح حلقات React useEffect اللانهائية — أخطاء مصفوفة التبعية، وعمليات حذف الكائن/الوظيفة، وجميع الأنماط الشائعة.”,
“url”: “https://techpulsesite.com/react-useeffect-infinite-loop-why-it-hap-ar/”,
“datePublished”: “2026-06-25T16:50:00+00:00”,
“dateModified”: “2026-06-29T04:14:41+00:00”,
“author”: {
“@type”: “Organization”,
“name”: “TechPulse Editorial Team”,
“url”: “https://techpulsesite.com”
},
“publisher”: {
“@type”: “Organization”,
“name”: “TechPulse”,
“url”: “https://techpulsesite.com”
},
“inLanguage”: “ar”
}
{
“@context”: “https://schema.org”,
“@type”: “TechArticle”,
“headline”: “رد فعل useEffect Infinite Loop: لماذا يحدث وكيفية إصلاحه بالضبط”,
“description”: “الدليل الكامل لتشخيص وإصلاح حلقات React useEffect اللانهائية — أخطاء مصفوفة التبعية، وعمليات حذف الكائن/الوظيفة، وجميع الأنماط الشائعة.”,
“url”: “https://techpulsesite.com/react-useeffect-infinite-loop-why-it-hap-ar/”,
“datePublished”: “2026-06-25T16:50:00+00:00”,
“dateModified”: “2026-06-21T05:59:46+00:00”,
“author”: {
“@type”: “Organization”,
“name”: “TechPulse Editorial Team”,
“url”: “https://techpulsesite.com”
},
“publisher”: {
“@type”: “Organization”,
“name”: “TechPulse”,
“url”: “https://techpulsesite.com”
},
“inLanguage”: “ar”
}
A رد فعل useEffect حلقة لا نهائية يعد أحد الأخطاء الأكثر شيوعًا للمطورين الذين يتعلمون الخطافات. يقوم المكون الخاص بك بإعادة العرض، مما يؤدي إلى تشغيل التأثير، مما يؤدي إلى عرض آخر، مما يؤدي إلى تشغيل التأثير مرة أخرى – حتى يتعطل المتصفح. إليك سبب حدوث ذلك وكيفية إصلاح كل متغير بالضبط.
📋 Table of Contents
- لماذا تحدث حلقات لا نهائية
- السبب الأول: تحديد الحالة بدون تبعيات (الأكثر شيوعًا)
- السبب 2: كائن في صفيف التبعية
- السبب 3: الوظيفة في صفيف التبعية
- السبب 4: تحديث الحالة مع الحالة باعتبارها تبعية
- السبب 5: صفيف في صفيف التبعية
- كيفية تصحيح أي حلقة لا نهائية
- مرجع سريع: متى يجب استخدام كل خطاف
- الأسئلة المتداولة
- الخلاصة
لماذا تحدث حلقات لا نهائية
تُنشئ كل عملية إعادة تصيير لمكون React مراجع جديدة للكائنات والمصفوفات والوظائف المحددة داخل المكون. إذا كانuseEffect تحتوي مصفوفة التبعية على إحدى هذه القيم، وترى React تبعية “جديدة” في كل تصيير – حتى لو كانت البيانات متطابقة منطقيًا – وتقوم بتشغيل التأثير مرة أخرى، مسببة إعادة تصيير أخرى، وإنشاء حلقة أخرى.
السبب الأول: تحديد الحالة بدون تبعيات (الأكثر شيوعًا)
// 🐛 Bug: runs after every render, sets state, causes re-render
useEffect(() => {
setCount(count + 1); // state update → re-render → effect runs again
}); // no dependency array = runs after EVERY render
// ✅ Fix: empty dependency array = run once on mount only
useEffect(() => {
setCount(prevCount => prevCount + 1);
}, []); // runs once
السبب 2: كائن في صفيف التبعية
// 🐛 Bug: new object reference on every render
function UserProfile({ userId }) {
const options = { method: 'GET', headers: { 'Auth': 'token' } }; // NEW object each render
useEffect(() => {
fetchUser(userId, options);
}, [options]); // options is always "new" → infinite loop
}
// ✅ Fix 1: move object outside component (if it's static)
const OPTIONS = { method: 'GET', headers: { 'Auth': 'token' } }; // defined once
function UserProfile({ userId }) {
useEffect(() => {
fetchUser(userId, OPTIONS);
}, [userId]); // only depends on userId
}
// ✅ Fix 2: useMemo if the object depends on props
function UserProfile({ userId, token }) {
const options = useMemo(
() => ({ method: 'GET', headers: { 'Auth': token } }),
[token] // only recreates when token changes
);
useEffect(() => {
fetchUser(userId, options);
}, [userId, options]);
}
السبب 3: الوظيفة في صفيف التبعية
// 🐛 Bug: new function reference on every render
function DataFetcher({ id }) {
const fetchData = async () => { // NEW function each render
const data = await api.get(id);
setData(data);
};
useEffect(() => {
fetchData();
}, [fetchData]); // fetchData is always "new" → infinite loop
}
// ✅ Fix: useCallback to memoize the function
function DataFetcher({ id }) {
const fetchData = useCallback(async () => {
const data = await api.get(id);
setData(data);
}, [id]); // only recreates when id changes
useEffect(() => {
fetchData();
}, [fetchData]); // stable reference now
}
// ✅ Alternative: define function INSIDE the effect
useEffect(() => {
const fetchData = async () => {
const data = await api.get(id);
setData(data);
};
fetchData();
}, [id]); // clean, no useCallback needed
السبب 4: تحديث الحالة مع الحالة باعتبارها تبعية
// 🐛 Bug: count is dependency AND being updated inside effect
useEffect(() => {
const timer = setInterval(() => {
setCount(count + 1); // depends on count → loop
}, 1000);
return () => clearInterval(timer);
}, [count]); // re-runs every time count changes
// ✅ Fix: use functional state update (no dependency on count)
useEffect(() => {
const timer = setInterval(() => {
setCount(prev => prev + 1); // no dependency on count needed
}, 1000);
return () => clearInterval(timer);
}, []); // runs once, updates count independently
السبب 5: صفيف في صفيف التبعية
// 🐛 Bug: new array reference on every render
function List({ items }) {
const filtered = items.filter(i => i.active); // NEW array each render
useEffect(() => {
processItems(filtered);
}, [filtered]); // always "new" → infinite loop
}
// ✅ Fix: useMemo to stabilize the array
function List({ items }) {
const filtered = useMemo(
() => items.filter(i => i.active),
[items]
);
useEffect(() => {
processItems(filtered);
}, [filtered]);
}
كيفية تصحيح أي حلقة لا نهائية
- أضف console.log قبل useEffect: تعرف على عدد مرات إعادة عرض المكون.
- قم بالتعليق على تحديث الحالة داخل التأثير: إذا توقفت الحلقة، فإن تحديث الحالة هو السبب.
- سجل كل تبعية:
console.log('dep1:', dep1, 'dep2:', dep2)داخل التأثير لمعرفة أي واحد تغير. - استخدم البرنامج المساعد لخطافات التفاعل ESLint:
eslint-plugin-react-hooksعلامات تفتقد التبعيات تلقائيًا.
مرجع سريع: متى يجب استخدام كل خطاف
| هوك | استخدم لـ |
|---|---|
| تأثير الاستخدام | الآثار الجانبية: جلب البيانات، الاشتراكات، معالجة DOM |
| استخدم مذكرة | القيم المحسوبة باهظة الثمن – تمنع إعادة الحساب في كل عرض |
| استخدام رد الاتصال | تم تمرير الوظائف كتبعيات أو دعائم للأطفال المحفوظة |
| استخدم المرجع | القيم التي لا ينبغي أن تؤدي إلى إعادة العرض عند تغييرها |
الأسئلة المتداولة
س: متى يجب علي استخدام مصفوفة تبعية فارغة؟
ج: عندما يجب تشغيل التأثير مرة واحدة فقط عند التحميل (على سبيل المثال، جلب البيانات الأولية، إعداد الاشتراك). كن حذرًا – فهو يُنشئ إغلاقًا على قيم الحالة الأولية.
س: هل يجب أن أقوم دائمًا بتضمين كل شيء في مصفوفة التبعية؟
ج: نعم، وفقًا لقواعد React. إذا تسبب تضمين شيء ما في تكرار حلقة، فإن الحل الحقيقي هو تثبيت هذه القيمة باستخدام useMemo/useCallback، وليس إزالتها من deps.
س: ما الفرق بين useMemo وuseCallback؟
A: useMemo يحفظ قيمة (على سبيل المثال، مصفوفة تمت تصفيتها). useCallback يحفظ وظيفة. كلاهما يمنع إعادة الإنشاء غير الضرورية في كل عرض.
س: لماذا تقوم React بتشغيل useEffect مرتين أثناء التطوير؟
ج: يقوم React 18 Strict Mode بتشغيل التأثيرات مرتين عمدًا أثناء التطوير للمساعدة في العثور على الآثار الجانبية التي لا يتم تنظيفها بشكل صحيح. هذا لا يحدث في الإنتاج.
س: هل يمكنني تعطيل قاعدة ESLint الشاملة؟
ج: يمكنك، ولكن لا ينبغي لك. القاعدة موجودة لأن التبعيات المفقودة تسبب أخطاء دقيقة. أصلح المشكلة الأساسية بدلاً من تعطيل التحذير.
الخلاصة
دائمًا ما تعود الحلقات اللانهائية المستخدمة في React useEffect إلى سبب جذري واحد:تبعية تنشئ مرجعًا جديدًا في كل عرض، مما يتسبب في إعادة تشغيل التأثير، مما يؤدي إلى تشغيل عرض آخر. الإصلاح دائمًا هو تثبيت هذا المرجع باستخدامuseMemo, useCallback, useRefأو عن طريق نقل القيمة خارج المكون. بمجرد استيعاب النموذج العقلي “نفس المرجع = عدم إعادة التشغيل”، يصبح من السهل منع هذه الأخطاء وتصحيحها بسرعة.
🔗 Share this article
✍️ Leave a Comment