تكرار السؤال: …
الإجابة المختصرة
تحدث عندما تلتقط الدالة متغيراً من الـ Scope الخارجي وقت إنشائها وتظل تحتفظ بقيمته القديمة حتى بعد تحديثه في دورات الـ render اللاحقة بسبب غيابه عن مصفوفة التبعيات (Dependency Array).
الشرح
دوال JavaScript تغلق على المتغيرات في نطاق تعريفها. في ريأكت، كل render له نطاقه وقيمه الخاصة. إذا قمت بإنشاء دالة useCallback أو useEffect ولم تضع المتغير المستخدم في مصفوفة التبعيات، فإن الـ callback سيحتفظ بنسخة المتغير من الـ render الأول للأبد.
مثال بالكود
// مثال Stale Closure مع setInterval
useEffect(() => {
const id = setInterval(() => {
// سيطبع 0 دائماً إذا لم يوضع count في التبعيات أو لم نستخدم updater
console.log("العدد الحالي:", count);
}, 1000);
return () => clearInterval(id);
}, []); // خطأ: غياب count من مصفوفة التبعيات
// الحل الصحيح: إما إدراج count أو استخدام functional updater
setCount(prev => prev + 1);أخطاء شائعة
- إسكات تحذيرات eslint-plugin-react-hooks بحذف مصفوفة التبعيات أو تجاهلها بدلاً من حل التبعية المفقودة.
أسئلة متابعة
- ما الفرق بين useMemo و useCallback ومتى يكون استخدامهما ضاراً بالأداء؟
- ما الفرق بين تمرير قيمة مباشرة لدالة setState وتمرير دالة تحديث وظيفية (Updater Function)؟