في هذا الدرس 6تصفّح المواضيع
في الوضع المعتاد، ترسم React عناصر HTML الخاصة بالمكون داخل عقدة أبيه المباشر في شجرة المتصفح. غير أن هذا التسلسل يسبب مشكلة بصرية شائعة عندما تحاول بطاقة مقيدة بخاصية overflow: hidden أو transform فتح نافذة حوارية شاملة أو قائمة منبثقة، إذ يقتطع المتصفح أطراف النافذة عند حدود البطاقة الضيقة!
تحل الدالة createPortal(children, domNode) المستوردة من حزمة react-dom هذه المعضلة بنقل الرسم الفيزيائي للعناصر إلى حاوية عليا مثل document.body مع بقاء المكون في موضعه المنطقي الكامل داخل شجرة React:
import { createPortal } from 'react-dom';
function FloatingNotice({ open, onClose }) {
if (!open) return null;
return createPortal(
<div role="status">
Saved! <button onClick={onClose}>OK</button>
</div>,
document.body
);
}
عند بناء نافذة حوارية قياسية باستخدام createPortal()، اجمع بين النقل البصري ومعايير الوصول الشامل ودعم الثيمات: أضف سمات role="dialog" وaria-modal="true" وaria-labelledby، واربط زر الهروب Escape عبر تأثير useEffect() مع دالة تنظيف، واستخدم متغيرات الألوان الدلالية لدعم الوضعين الفاتح والداكن:
useEffect(() => {
if (!open) return;
const onKey = (e) => e.key === 'Escape' && onClose();
window.addEventListener('keydown', onKey);
return () => {
window.removeEventListener('keydown', onKey);
};
}, [open, onClose]);
هناك تفصيل معماري بالغ الأهمية يفاجئ حتى المطورين المتمرسين: تصعد الأحداث التفاعلية داخل البوابة عبر شجرة مكونات React المنطقية، وليس عبر شجرة HTML الفيزيائية فقط!
فإذا وضعت بوابة نافذة حوارية داخل عنصر أب يملك معالج onClick، فإن النقر على زر الإغلاق داخل النافذة المرسومة في document.body سيصعد عبر شجرة React ويشغّل معالج النقر في الأب ما لم توقف الانتشار عبر e.stopPropagation() أو تضع مكون النافذة خارج العنصر القابل للنقر.
كما تحمي البوابات حدود التخطيط البصري، تحمي حدود عزل الأخطاء (Error Boundaries) استقرار التطبيق وقت التشغيل. فإذا واجهت أداة فرعية بيانات تالفة غير متوقعة أثناء التصيير—مثل قراءة خاصية من كائن قيمته null—يُرمى استثناء برمجي فوري.
في السلوك الافتراضي غير المحمي، تزيل React شجرة التطبيق بأكملها عند وقوع خطأ تصيير غير معالج، فتظهر شاشة فارغة بدلاً من بقاء واجهة معطوبة قد تضلل المستخدم.
يحيط غلاف Error Boundary بالأقسام المستقلة في شاشتك—كمخطط الأسهم أو قسم التعليقات أو المكونات الكسولة—ليعرض بطاقة بديلة آمنة مع زر إعادة المحاولة عند تعطل ذلك القسم وحده، بينما تواصل بقية الصفحة عملها دون انقطاع.
انتبه لحقيقة معمارية خاصة في React الحديثة: تُعد حدود الأخطاء الاستثناء المعماري الوحيد الذي لا يزال يعتمد داخلياً على الدالة الثابتة getDerivedStateFromError ودالة التسجيل componentDidCatch لعدم توفر خطاف مكافئ لها بعد. وفي المشاريع العملية تكتب هذا الغلاف الصغير مرة واحدة فقط في ملف مساعد مشترك وتبقى جميع مكونات تطبيقك دوالَّ حديثة بنسبة 100%:
class ErrorBoundary extends Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
render() {
const { hasError } = this.state;
return hasError
? this.props.fallback
: this.props.children;
}
}
من الضروري التمييز بدقة بين ما تصطاده حدود الأخطاء وما لا يدخل في نطاقها: تلتقط ErrorBoundary الأخطاء المرمية أثناء طور التصيير وبما يشمل فشل تحميل حزم React.lazy، لكنها لا تلتقط أخطاء دوال الأحداث مثل onClick ولا أخطاء fetch غير المتزامنة؛ فتلك تُعالج ببنية try / catch وحالة الخطأ الاعتيادية كما تعلمت في الوحدة الثامنة. يوضح الجدول التالي آلية التعامل مع كل نوع:
| مصدر الخطأ البرمجي | هل تلتقطه ErrorBoundary؟ | الأسلوب الهندسي الصحيح للمعالجة |
|---|---|---|
| قراءة خاصية فارغة أثناء تصيير JSX | نعم — تلتقطه وتعزله فوراً | تغليف الأقسام المستقلة بحد ErrorBoundary |
| فشل تحميل حزمة React.lazy الشبكية | نعم — يلتقطه الحد المحيط بـ Suspense | عرض بطاقة إعادة المحاولة داخل واجهة البديل |
| خطأ داخل معالج حدث مثل onClick | لا — يقع خارج طور التصيير | استخدام try/catch وتحديث حالة الخطأ في المكون |
| رفض طلب fetch أو مؤقت غير متزامن | لا — يعمل في نطاق غير متزامن | معالجة رفض الوعد وتخزين رسالة الخطأ بالحالة |
ملخص الدرس
حصاد الدرسمراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي
ماذا تعلّمت في هذا الدرس؟
أتقنت في هذا الدرس إخراج النوافذ الحوارية السليمة عبر createPortal لتجاوز قيود القص مع فهم صعود الأحداث في شجرة React، وعزل أعطال التصيير بحدود Error Boundaries لحماية استقرار التطبيق. الخطوة التالية: انتقل الآن إلى الدرس رقم 47 «مفهوم التوجيه في تطبيقات الصفحة الواحدة وإعداد React Router» لمواصلة البناء التراكمي المتدرج في مسار React الحديث.
سجّل الدخول لحفظ تقدمك
تابع إنجاز المواضيع والمصطلحات والمهام، وكمّل من آخر خطوة على أي جهاز.
المصطلحات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 Portal البوابة البرمجية Portal
- آلية عبر دالة createPortal تتيح رسم عناصر المكون في عقدة DOM خارجية مثل document.body مع بقائه منطقياً داخل شجرة React.
- للمراجعة
- 02 Stacking Context سياق الترتيب الطبقي
- قواعد ترتيب الطبقات في المتصفح الناتجة عن خصائص مثل overflow وz-index والتي تتجاوزها البوابات بنجاح.
- للمراجعة
- 03 Error Boundary حد عزل الأخطاء
- مكون غلاف وقائي في React يلتقط أخطاء التصيير المرمية في شجرته الفرعية ويعرض واجهة بديلة آمنة دون انهيار الصفحة.
- للمراجعة
- 04 Fallback UI واجهة الاستعادة البديلة
- بطاقة تنبيه آمنة قابلة لإعادة المحاولة تحل محل القسم المتعطل لحماية تجربة المستخدم.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
الاختصارات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 ARIA ARIA
- Accessible Rich Internet Applications
- سمات إتاحة قياسية مثل role="dialog" وaria-modal="true" ضرورية لدعم قارئات الشاشة في النوافذ الحوارية.
- للمراجعة
- 02 DOM DOM
- Document Object Model
- شجرة المستند الفيزيائية التي تلحق بها البوابة عناصر النافذة مباشرة داخل document.body.
- للمراجعة
- 03 CSS CSS
- Cascading Style Sheets
- طبقة التنسيق التي قد تقتطع القوائم المنبثقة غير المخرجة عبر بوابة عند استخدام overflow: hidden.
- للمراجعة
- 04 UX UX
- User Experience
- جودة واستمرارية تجربة المستخدم عند عزل عطل أداة فرعية دون فقدان بيانات بقية الشاشة.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
مهامك قبل الاختبار
خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.
-
شغّل مثال ProjectSettings في محرر التجريب وافتح نافذة الأرشفة وجرّب إغلاقها بمفتاح Escape تارة وبالنقر على الخلفية الداكنة تارة أخرى.
-
اكتب نصاً خاصاً في حقل الملاحظات المجاور داخل مثال ResilientDashboard ثم اضغط محاكاة العطل وتأكد من بقاء نصك سليماً ثم أعد تفعيل الأداة.
تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.
اختبر فهمك.
ووصلها للإتقان.
كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.
أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.
الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.
لمحة عن التحدي10 أسئلة تنتظرك +
من أي حزمة برمجية تُستورد الدالة createPortal في تطبيقات ويب React؟
تُستورد دالة createPortal مباشرة من الحزمة الخاصة بالمتصفح react-dom.
ما المشكلة البصرية الأساسية التي تحلها دالة createPortal عند رسم النوافذ والقوائم العائمة؟
تُخرج العنصر من قيود القص البصري overflow: hidden وسياقات الترتيب الضيقة للحاويات الأب.
يظل المكون المرسوم عبر createPortal في document.body قادراً على قراءة قيم السياق Context من آبائه في شجرة React.
صواب؛ تغير البوابة مكان عقد HTML الفيزيائي فقط بينما يبقى المكون متصلاً بالكامل بشجرة السياق في React.
كيف تصعد أحداث النقر المتولدة داخل نافذة مرسومة عبر createPortal؟
تصعد الأحداث عبر شجرة مكونات React المنطقية لتصل إلى آباء المكون في JSX.
ما التفاعل اللوحي وسمات الإتاحة الضرورية عند بناء نافذة حوارية قياسية؟
توفير سمات role="dialog" وaria-modal="true" وربط العنوان ودعم الإغلاق بمفتاح Escape.
ماذا تفعل React افتراضياً إذا رمى مكون فرعي خطأ غير معالج أثناء التصيير دون وجود حد عزل أخطاء؟
تزيل React شجرة مكونات التطبيق بأكملها لتجنب بقاء واجهة معطوبة أو مضللة أمام المستخدم.
يحافظ تغليف مخطط بياني بحد Error Boundary على بقاء النماذج والملاحظات المجاورة شغالة بأمان حتى لو تعطل المخطط أثناء الرسم.
صواب؛ يُستبدل القسم المتعطل وحده بواجهة الاستعادة البديلة بينما تستمر بقية الشاشة بالعمل.
تلتقط حدود Error Boundaries تلقائياً الأخطاء التي تحدث داخل دوال النقر onClick على الأزرار.
خطأ؛ تعمل معالجات الأحداث خارج طور التصيير، لذا تُعالج أخطاؤها عبر try/catch وتحديث حالة الخطأ.
كيف تعالج فشل تحميل حزمة مكون كسول React.lazy عند انقطاع اتصال الشبكة لدى المستخدم؟
بوضع غلاف Error Boundary يحيط بحد الانتظار Suspense لالتقاط الفشل وعرض بطاقة إعادة المحاولة.
لماذا يكتفي مشروع React الحديث بملف غلاف ErrorBoundary واحد فقط بينما تُبنى سائر المكونات كدوال؟
لأن خطافات React لا تتضمن بعد بديلاً لدالة getDerivedStateFromError، ويكفي غلاف واحد مشترك لحماية جميع المكونات الدالية.