أتقِن آلية التعليق، وتحميل المكوّنات الكسول، وتقسيم الحزمة.
افتح هذا الدرس في Kodokonيعتمد Suspense على آلية قليلة الشهرة: المكوّن الذي لا يملك بعدُ بياناته أو شيفرته يُعلّق عرضه. تحت الغطاء، تُطلق التطبيقة الحالية وعداً يعترضه React تماماً كما يعترض خطأً. عندئذٍ يصعد React إلى أقرب حدّ <Suspense>، فيعرض fallback الخاص به، ثم يعيد عرض الشجرة الفرعية بمجرّد أن يُحلّ الوعد. إنه تفصيل من تفاصيل التطبيق (لا تُطلق وعداً بنفسك أبداً)، لكنه يفسّر كل السلوك القابل للملاحظة: يعمل الحدّ عمل catch تصريحي للعمل غير المتزامن. الاستعمال التاريخي هو تقسيم الشيفرة بواسطة React.lazy.
import { lazy, Suspense } from 'react';
const Chart = lazy(() => import('./Chart'));
function Dashboard() {
return (
<Suspense fallback={<Spinner />}>
<Chart points={data} />
</Suspense>
);
}يتوقّع lazy دالة تُرجِع وعداً يُحَلّ إلى وحدة ذات تصدير default. أمّا التقسيم نفسه فهو مهمّة أداة الحزم: كل import() ديناميكي يصبح نقطة تقسيم وينتج قطعة منفصلة تُحمَّل عند الطلب. دقيقة شائعة في قواعد الشيفرة الحقيقية: كثيراً ما تكون مكوّناتك تصديرات مُسمّاة. عندئذٍ عليك تكييف الوحدة أثناء التشغيل.
const Chart = lazy(() =>
import('./charts').then((module) => ({
default: module.Chart,
}))
);الجزء الشائك في الإنتاج: أثناء التنقّل، يمكن لمحتوى معروض فعلاً أن يُعلَّق من جديد (مسار جديد، قطعة جديدة) فيُستبدَل فجأةً بالـ fallback. منذ React 18، يغيّر تحديث مغلّف بـ startTransition هذا السلوك: يُبقي React الواجهة السابقة على الشاشة بينما يُعلَّق العرض الجديد في الخلفية، ولا يعرض الـ fallback إلا للمحتوى الذي لم يُكشَف قطّ. كما تتركّب الحدود في العمق: عدّة حدود <Suspense> متداخلة تتيح كشف الواجهة منطقةً منطقةً، من الهيكل العام نزولاً إلى التفاصيل.
const [isPending, startTransition] = useTransition();
function openTab(nextTab) {
startTransition(() => {
setTab(nextTab);
});
}
// The current tab stays visible while the new
// one loads, instead of dropping back to the fallback.React.lazy؟