في هذا الدرس 6تصفّح المواضيع
عند بناء مشروع React للإنتاج عبر أداة Vite، تندمج جميع عبارات import الثابتة في أعلى الملفات لتشكيل حزمة JavaScript موحدة. ومع نمو المشروع وإضافة محررات النصوص الغنية ومكتبات الرسوم البيانية، تتضخم هذه الحزمة لتؤخر ظهور الشاشة الأولى، خاصة على اتصالات الهواتف المحمولة.
يعالج تقسيم الكود (Code Splitting) هذه المشكلة بتجزئة التطبيق إلى حزم صغيرة، بحيث يحمّل المتصفح الواجهة الأساسية فوراً ويؤجل جلب المزايا الثقيلة لحين فتحها فعلياً.
تجعل مكتبة React تقسيم المكونات عملية تصريحية بسيطة عبر الدالة lazy(load) المستوردة من حزمة react. بدلاً من الاستيراد الثابت، نمرر دالة تستدعي الاستيراد الديناميكي القياسي import("./ReportChart.jsx").
تُرجع عبارة الاستيراد الديناميكي وعداً (Promise) يُحلّ إلى وحدة برمجية تصدّر المكون كـ تصدير افتراضي (export default)، ولا تطلب React تحميل هذا الملف إطلاقاً حتى تحاول الواجهة رسم المكون لأول مرة.
بما أن المكون المعرف عبر lazy() يُجلب بشكل غير متزامن عند عرضه الأول، تحتاج React لمعرفة ما يجب إظهاره للمستخدم خلال لحظات التحميل؛ ولذلك نحيط المكون الكسول بحد انتظار <Suspense fallback={...}>.
تقبل خاصية fallback أي عنصر JSX خفيف مثل بطاقة هيكلية مؤقتة (Skeleton)، ثم تستبدله React تلقائياً بالمكون الحقيقي فور اكتمال وصول الحزمة:
import { lazy, Suspense } from 'react';
const ReportChart = lazy(
() => import('./ReportChart.jsx')
);
function AnalyticsTab() {
return (
<Suspense fallback={<p>Loading report...</p>}>
<ReportChart />
</Suspense>
);
}
يؤثر موضع عنصر <Suspense> مباشرة في جودة تجربة المستخدم؛ فوضعه حول الجذر الكلي للتطبيق يخفي الرأس وشريط التنقل خلف شاشة انتظار فارغة بمجرد طلب أي أداة فرعية.
وزّع حدود <Suspense> بذكاء حول منطقة المحتوى المتغيرة فقط ليبقى الهيكل الرئيسي للتطبيق ظاهراً، واجمع البطاقات المترابطة تحت حد واحد إذا أردت ظهورها معاً في لحظة متناسقة:
function StudioLayout({ tab }) {
return (
<main>
<TopToolbar />
<Suspense fallback={<p>Loading tool...</p>}>
{tab === 'export' ? <LazyExporter /> : <Home />}
</Suspense>
</main>
);
}
تقرن إصدارات React الحديثة مكون <Suspense> بخطافين متقدمين للحفاظ على سلاسة الاستجابة هما useTransition() وuseDeferredValue().
عند تغليف تبديل التبويب داخل startTransition(() => setTab("reports"))، تعامله React كتحديث غير عاجل فتُبقي التبويب الحالي ظاهراً وقابلاً للتفاعل مع راية isPending بدلاً من إخفاء الشاشة فجأة. وبالمثل يتيح useDeferredValue(query) تحديث حقل الكتابة فوراً بينما تلحق به القائمة الضخمة بسلاسة دون تجميد لوحة المفاتيح:
import {
useDeferredValue,
useState,
useTransition,
} from 'react';
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
const [isPending, startTransition] = useTransition();
التزم بأربع ممارسات احترافية عند تقسيم الحزم في مشاريع الإنتاج: قسّم عند الحدود الطبيعية الكبرى كاللوحات الثانوية والمحررات الثقيلة والشاشات المستقلة، وعرّف استيرادات lazy() دائماً في أعلى الملف، وصمّم بدائل انتظار مطابقة لأبعاد المكون لمنع القفز البصري، واحمِ الحزم الكسولة بحدود عزل الأخطاء التي سنتعلمها في الدرس القادم تحسباً لانقطاع الشبكة. يلخص الجدول التالي تكامل هذه الأدوات:
| الأداة في React | المسؤولية الأساسية | الحالة المثلى في الواجهة |
|---|---|---|
| الدالة React.lazy | فصل المكون في حزمة مستقلة تُحمل عند الطلب | المخططات الثقيلة والمحررات المتقدمة والشاشات الفرعية |
| مكون الانتظار Suspense | عرض واجهة بديلة مؤقتة ريثما تجهز الحزمة | إحاطة مناطق المحتوى مع إبقاء الرأس والقائمة ظاهرين |
| خطاف useTransition | تصنيف تحديث الحالة كتبديل غير عاجل قابل للمقاطعة | التنقل السلس بين التبويبات دون إخفاء المحتوى الحالي |
| خطاف useDeferredValue | تأجيل القيمة المشتقة لإبقاء حقل الإدخال لحظياً | البحث الفوري السلس داخل قوائم وجداول كبيرة |
ملخص الدرس
حصاد الدرسمراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي
ماذا تعلّمت في هذا الدرس؟
تعلمت في هذا الدرس أثر تضخم الحزم على بدء التشغيل، وكيفية تقسيم المكونات الثقيلة عند الطلب عبر React.lazy، وإدارة حدود الانتظار بمكون Suspense، والحفاظ على استجابة الواجهة عبر useTransition وuseDeferredValue. الخطوة التالية: انتقل الآن إلى الدرس رقم 46 «العرض عبر البوابات createPortal وحدود عزل الأخطاء» لمواصلة البناء التراكمي المتدرج في مسار React الحديث.
سجّل الدخول لحفظ تقدمك
تابع إنجاز المواضيع والمصطلحات والمهام، وكمّل من آخر خطوة على أي جهاز.
المصطلحات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 Code Splitting تقسيم الكود
- تجزئة حزمة JavaScript الكبيرة إلى ملفات فرعية صغيرة تُحمل عند الطلب فقط لتسريع فتح التطبيق الأولي.
- للمراجعة
- 02 React.lazy التحميل الكسول lazy
- دالة في React تتيح تعريف مكون يُستورد ديناميكياً عبر الشبكة عند محاولة عرضه لأول مرة.
- للمراجعة
- 03 Suspense Boundary حد الانتظار Suspense
- غلاف تصريحي في React يعرض واجهة انتظار بديلة ريثما تكتمل جاهزية المكونات الكسولة بداخله.
- للمراجعة
- 04 Transition التحديث غير العاجل
- تحديث حالة منخفض الأولوية يُدار عبر useTransition بحيث لا يعطل الكتابة الفورية أو النقرات العاجلة.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
الاختصارات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 ESM ESM
- ECMAScript Modules
- نظام الوحدات القياسي في JavaScript الذي يوفر دالة الاستيراد الديناميكي المستخدمة مع React.lazy.
- للمراجعة
- 02 FCP FCP
- First Contentful Paint
- مقياس سرعة ظهور أول محتوى مرئي للمستخدم، ويتحسن مباشرة بتقليص حجم الحزمة الأولية.
- للمراجعة
- 03 CLS CLS
- Cumulative Layout Shift
- مقياس ثبات التخطيط البصري الذي نحميه بتصميم هياكل انتظار مطابقة لأبعاد المكون الفعلي.
- للمراجعة
- 04 INP INP
- Interaction to Next Paint
- مقياس سرعة استجابة الواجهة لتفاعل المستخدم، ويتحسن بعزل التحديثات الثقيلة في انتقالات سلسة.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
مهامك قبل الاختبار
خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.
-
شغّل مثال AnalyticsWorkspace واضغط زر تحميل التوقعات لملاحظة واجهة الانتظار، ثم أغلق اللوحة وأعد فتحها للتأكد من ظهورها الفوري من الذاكرة.
-
اكتب كلمات بحث وبدّل بين فئات SmoothCatalog في محرر التجريب لمراقبة بقاء الكتابة لحظية وسلسة دون اختفاء القائمة.
تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.
اختبر فهمك.
ووصلها للإتقان.
كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.
أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.
الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.
لمحة عن التحدي10 أسئلة تنتظرك +
ما الهدف الهندسي الأساسي من تقسيم الكود Code Splitting في تطبيقات React؟
تقليص حجم الحزمة الأولية وتأجيل تحميل اللوحات والمكتبات الثقيلة لحين طلب المستخدم لها.
ماذا يشترط أن تصدّر الوحدة المستوردة ديناميكياً داخل الدالة React.lazy؟
تشترط دالة React.lazy أن يحتوي الملف المستورد على تصدير افتراضي default export لمكون React.
ما المكون المدمج في React المسؤول عن عرض واجهة بديلة مؤقتة أثناء انتظار تحميل مكون كسول؟
يلتقط مكون Suspense حالة تحميل المكون الكسول ويعرض العنصر الممرر في خاصية fallback.
ينبغي تعريف متغير lazy() داخل جسم دالة المكون الأب ليُعاد إنشاؤه في كل تصيير.
خطأ؛ يجب تعريف lazy في المستوى الأعلى للملف خارج المكونات كي لا تُمسح حالة المكون في كل تصيير.
بعد اكتمال تحميل مكون React.lazy للمرة الأولى، تعيد مرات الفتح التالية استخدامه من الذاكرة دون إعادة تحميله.
صواب؛ تحتفظ React والمتصفح بالوحدة المحملة فيُعرض المكون فوراً عند فتحه مجدداً.
لماذا يُفضل غالباً وضع حد Suspense حول منطقة المحتوى المتغيرة بدلاً من تغليف الرأس والقائمة معها؟
لإبقاء شريط التنقل وهيكل الصفحة الرئيسي مرئياً وتفاعلياً أمام المستخدم أثناء انتظار القسم الفرعي.
كيف يحسّن تغليف تحديث التبويب داخل startTransition تجربة المستخدم مع المكونات الكسولة؟
يُبقي التبويب الحالي مرئياً وتفاعلياً مع إمكانية إظهار مؤشر خفيف ريثما يجهز التبويب الجديد.
أي خطاف يسمح بتحديث حقل النص لحظياً مع تأجيل تحديث القائمة المشتقة الثقيلة بأولوية أقل؟
يعيد الخطاف useDeferredValue نسخة مؤجلة متدرجة من القيمة السريعة التغير لحماية سلاسة الكتابة.
يساعد تصميم هيكل الانتظار fallback بأبعاد مقاربة للمكون الحقيقي على منع القفز البصري للتخطيط CLS.
صواب؛ فحجز المساحة المناسبة يمنع اهتزاز وقفز العناصر المجاورة عند ظهور المكون المحمل.
أي أجزاء التطبيق التالية تُعد الأنسب لتطبيق التحميل الكسول عبر React.lazy؟
اللوحات الثانوية الثقيلة ومكتبات المخططات والمحررات المتقدمة والشاشات المستقلة.