في هذا الدرس 6تصفّح المواضيع
تحوّل مكونات React النقية الخصائص والحالة إلى عناصر JSX، بينما تستجيب معالجات الأحداث لنقرات محددة كالضغط على زر الحفظ. لكن بعض المكونات تحتاج إلى البقاء متزامنة مع أنظمة خارجية تقع خارج سيطرة React — مثل تحديث عنوان تبويب المتصفح document.title، أو مزامنة تفضيل المستخدم في localStorage، أو الاتصال بغرفة محادثة حية — لمجرد وجود المكون معروضاً على الشاشة.
يتيح خطاف useEffect(setup, dependencies) تنفيذ هذه التأثيرات الجانبية التزامنية بأمان خارج جسم التصيير النقي.
const [unread, setUnread] = useState(2);
useEffect(() => {
document.title = '(' + unread + ') CloseTag Inbox';
}, [unread]);
يمثل توقيت التنفيذ ميزة جوهرية في useEffect؛ إذ تؤجل React استدعاء دالة التأثير حتى اكتمال مرحلة الاعتماد ورسم المتصفح للبكسلات فعلياً على الشاشة. ففي البداية تحسب الدالة مخرجات JSX، ثم يحدّث المتصفح الشاشة أمام المستخدم، وبعدها تنطلق دالة التأثير.
بفضل هذا الترتيب لا تتسبب مهام المزامنة الخارجية في حجب ظهور الواجهة أو تأخير استجابتها البصرية.
لا تُختار عناصر مصفوفة الاعتماديات عشوائياً، بل يجب إدراج كل قيمة تفاعلية تقرؤها دالة التأثير بداخلها (سواء كانت من props أو state أو متغيراً مشتقاً منهما داخل المكون) ضمن المصفوفة [dep1, dep2] دون إخفاء.
وعندما تتغير حالة أخرى غير مدرجة لأن التأثير لا يستخدمها — ككتابة مسودة رسالة بينما معرّف الغرفة roomId ثابت — تتخطى React إعادة تشغيل التأثير بكفاءة تامة.
useEffect(() => {
setSyncCount((c) => c + 1);
}, [roomId]);
// Typing in draft input never re-triggers room sync!
يعمل كل استدعاء لخطاف useEffect وفق إحدى ثلاث حالات واضحة لمصفوفة الاعتماديات:
- مصفوفة بقيم محددة
[a, b]: يعمل بعد التركيب الأولي ثم بعد أي تصيير تتغير فيه قيمةaأوb. - مصفوفة فارغة
[]: يعمل مرة واحدة عند التركيب الفعلي لأنه لا يقرأ أي قيم تفاعلية متغيرة داخل المكون. - إغفال المصفوفة تماماً
useEffect(fn): يعمل عقب كل تصيير بلا استثناء، وهو سلوك نادر الحاجة.
تقع الحلقة اللانهائية (Infinite Loop) عندما يحدّث التأثير متغير حالة بلا شرط بينما يدرج المتغير نفسه في اعتمادياته — مثل كتابة setCount(count + 1) مع الاعتماد على [count] أو نسيان مصفوفة الاعتماديات كلياً؛ فكل تحديث يشعل تصييراً يشغل التأثير من جديد بلا توقف.
امنع الحلقات بجعل التأثير يكتب إلى النظام الخارجي كـ localStorage باتجاه واحد منظم، أو باستخدام دالة التحديث المعتمدة على القيمة السابقة عند الضرورة.
const [fontScale, setFontScale] = useState(16);
useEffect(() => {
try {
const val = String(fontScale);
localStorage.setItem('ct_font_px', val);
} catch {}
}, [fontScale]);
تقارن React كل عنصر في مصفوفة الاعتماديات بقيمته في التصيير السابق عبر خوارزمية Object.is(prevDep, nextDep). تتطابق النصوص والأرقام والقيم المنطقية بتساوي قيمها، أما إنشاء كائن جديد { roomId } أو مصفوفة جديدة مباشرة أثناء جسم التصيير فينتج عنوان ذاكرة مختلفاً في كل مرة فيعيد تشغيل التأثير بلا مبرر!
لضمان استقرار الاعتماديات، أنشئ كائنات الإعداد داخل دالة useEffect نفسها واعتمد في المصفوفة على القيم الأولية المباشرة مثل [serverUrl, roomId]، أو ارفع الثوابت الساكنة خارج المكون. يلخص الجدول التالي القواعد الكاملة:
| نمط مصفوفة الاعتماديات | توقيت تشغيل التأثير | الحالة الهندسية المناسبة |
|---|---|---|
| قيم أولية مثل [roomId, theme] | عند التركيب وعند تغير أي من القيمتين فقط | مزامنة عنوان الصفحة أو القناة أو التخزين المحلي |
| مصفوفة فارغة [] | مرة واحدة بعد رسم التركيب الأولي للمكون | تهيئة أداة خارجية لا تقرأ أي حالة أو خاصية |
| بدون تمرير مصفوفة ثانية | عقب كل تصيير يمر به المكون بلا استثناء | تشخيص نادر؛ خطر جداً إذا استُدعيت داخله setState |
| كائن منشأ بالعرض [{ id }] | في كل تصيير لأن المرجع الجديد يختلف بالذاكرة | نمط خاطئ — أنشئ الكائن داخل التأثير واعتمد على [id] |
ملخص الدرس
حصاد الدرسمراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي
ماذا تعلّمت في هذا الدرس؟
تعلّمت في هذا الدرس كيف يزامن خطاف useEffect مكونات React مع الأنظمة الخارجية بعد رسم الشاشة، وأتقنت الحالات الثلاث لمصفوفة الاعتماديات، ومنعت حلقات التصيير اللانهائية ومشكلة المراجع المتغيرة مع مقارنة Object.is. الخطوة التالية: انتقل الآن إلى الدرس رقم 35 «دوال تنظيف التأثيرات ودورة حياة useEffect» لمواصلة البناء التراكمي المتدرج في مسار React الحديث.
سجّل الدخول لحفظ تقدمك
تابع إنجاز المواضيع والمصطلحات والمهام، وكمّل من آخر خطوة على أي جهاز.
المصطلحات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 Side Effect التأثير الجانبي
- عملية تتجاوز حساب عناصر JSX النقية للتخاطب مع واجهات المتصفح أو التخزين أو الشبكة.
- للمراجعة
- 02 Dependency Array مصفوفة الاعتماديات
- المعامل الثاني في useEffect الذي يضم كافة القيم التفاعلية المقروءة داخل دالة التأثير.
- للمراجعة
- 03 Reactive Value القيمة التفاعلية
- الخصائص ومتغيرات الحالة وكل متغير محلي يُشتق منها داخل جسم دالة المكون.
- للمراجعة
- 04 Stale Closure الإغلاق المتقادم
- خطأ برمجي ينشأ عند إغفال متغير من مصفوفة الاعتماديات فيظل التأثير يقرأ نسخته القديمة.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
الاختصارات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 DOM DOM
- Document Object Model
- بنية المستند في المتصفح بما تشمله من خصائص عامة مثل document.title.
- للمراجعة
- 02 API API
- Application Programming Interface
- واجهات المتصفح أو الخادم الخارجية التي نربطها بحالة المكون عبر التأثيرات.
- للمراجعة
- 03 UI UI
- User Interface
- الواجهة المرئية التي يرسمها المتصفح للمستخدم أولاً قبل تشغيل دوال useEffect.
- للمراجعة
- 04 JSON JSON
- JavaScript Object Notation
- صيغة نصية قياسية تُستخدم لتحويل كائنات التفضيلات عند حفظها في التخزين المحلي.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
مهامك قبل الاختبار
خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.
-
افتح مثال InboxHeaderSync وعدّل دالة useEffect بحيث يصبح العنوان All Caught Up — CloseTag عندما تكون الرسائل صفراً.
-
أضف حالة جودة الاتصال إلى مثال StudyRoomConnector وأدرجها في مصفوفة الاعتماديات مع roomId لمراقبة إعادة المزامنة.
تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.
اختبر فهمك.
ووصلها للإتقان.
كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.
أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.
الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.
لمحة عن التحدي10 أسئلة تنتظرك +
متى تنفذ مكتبة React دالة الإعداد داخل useEffect في الحالة القياسية؟
تعمل دالة useEffect بعد اعتماد التغييرات وإتمام المتصفح لرسم الشاشة المحدثة أمام المستخدم.
ماذا يحدث عند حذف المعامل الثاني تماماً وكتابة useEffect(() => { ... }) بدون مصفوفة؟
عند غياب مصفوفة الاعتماديات يعمل التأثير بعد كل تصيير يمر به المكون بلا استثناء.
يجب إدراج كل متغير حالة أو خاصية تفاعلية تقرؤها دالة useEffect ضمن مصفوفة اعتمادياتها.
صواب؛ فإدراج جميع القيم التفاعلية المقروءة يمنع الإغلاقات المتقادمة ويضمن صحة المزامنة.
لماذا يؤدي استدعاء setCount(count + 1) دون شرط داخل useEffect يعتمد على [count] إلى تجميد المتصفح؟
لأن تحديث count يشعل إعادة تصيير بقيمة جديدة، فترصد المصفوفة التغيير وتعيد تشغيل التأثير في حلقة لا نهائية.
ما دالة المقارنة القياسية التي تستخدمها React لمقارنة عناصر مصفوفة الاعتماديات بين تصييرين؟
تفحص React كل خانة في مصفوفة الاعتماديات باستخدام المقارنة الدقيقة Object.is.
تمرير كائن يُنشأ أثناء جسم التصيير مثل const options = { roomId } داخل [options] يعيد تشغيل التأثير في كل تصيير.
صواب؛ لأن كل تصيير ينشئ كائناً بعنوان ذاكرة جديد فتكون نتيجة مقارنة Object.is خطأ دائماً.
كيف نعالج بنظافة تأثيراً يعيد التشغيل في كل تصيير بسبب إنشاء الكائن options = { serverUrl, roomId } أثناء العرض؟
ننقل إنشاء كائن options إلى داخل دالة useEffect نفسها ونضع القيم الأولية [serverUrl, roomId] في الاعتماديات.
تعني المصفوفة الفارغة [] أن التأثير لا يقرأ أي حالة أو خاصية تفاعلية متغيرة فيكتفي بالعمل عند التركيب.
صواب؛ لعدم اعتماده على أي قيمة تفاعلية في المكون فإنه يعمل بعد التركيب الأولي فقط.
أي مهمة مما يلي تُعد حالة استخدام صحيحة لمزامنة نظام خارجي عبر useEffect؟
تحديث خاصية المتصفح الخارجية document.title بناءً على حالة الرسائل يمثل مزامنة حقيقية مع نظام خارجي.
تتمتع دوال تحديث الحالة القادمة من useState بهوية ثابتة عبر التصييرات ولا تسبب إغلاقات قديمة في التأثير.
صواب؛ تضمن مكتبة React بقاء مرجع دالة التحديث ثابتاً طوال عمر نسخة المكون.