تخطَّ إلى المحتوى

ملف loading.tsx ليس مؤشّر تحميل

ملف التحميل حدّ Suspense يلفّ مقطع مسار كاملًا، أي أنه يقرّر كم من صفحتك ينتظر أبطأ استعلام لديك. ومعظم هذه الملفات موضوعة بالمصادفة.

3 دقيقة قراءة

وضع loading.tsx في مسارٍ يمنحك حالة تحميل فورية، وعند هذا الحدّ تتوقّف معظم الفرق عن القراءة. الملفّ ليس مكوّن مؤشّر تحميل. إنه البديل الاحتياطي لحدّ Suspense يلفّه Next.js حول المقطع كلّه، والحدّ هو الجزء المهم.

ومعنى ذلك عمليًا: كل ما داخل المقطع ينتظر أبطأ ما فيه. فملف loading.tsx في أعلى مسار لوحة تحكّم يحوّل صفحةً فيها ترويسة سريعة وشريط جانبي سريع ورسم بياني بطيء إلى صفحة لا تعرض شيئًا حتى يجهز الرسم.

كانت الترويسة والشريط جاهزَين خلال 40 مللي ثانية. ورأى الزائر هيكلًا فارغًا ثانيتين، لأن الحدّ رُسِم حول الثلاثة معًا.

أين ينتمي الحدّ

حول الشيء البطيء، لا حول الصفحة.

// app/dashboard/page.tsx - لا loading.tsx في هذا المجلّد.
import { Suspense } from 'react';
 
export default function Dashboard() {
  return (
    <>
      <Header />       {/* يُعرَض فورًا */}
      <Sidebar />      {/* يُعرَض فورًا */}
 
      <Suspense fallback={<ChartSkeleton />}>
        <RevenueChart />   {/* الشيء الوحيد الذي ينتظر */}
      </Suspense>
    </>
  );
}

يتدفّق الهيكل أولًا، ويصل الرسم حين يصل، ويكون لدى الزائر في الأثناء ما يقرأه وما ينقر عليه. الزمن الإجمالي نفسه، والتجربة مختلفة تمامًا - ومؤشّر LCP أفضل بكثير، لأن أكبر عنصر مرسوم لم يعد هيكلًا فارغًا.

متى يكون ملف التحميل على مستوى المسار صحيحًا

ليس خطأً دائمًا. استعمله حين يعتمد المقطع كلّه فعلًا على جلبٍ واحد - صفحة مقال لا تكون صفحةً بدون المقال، أو عرض تفصيلي هو سجلّ واحد. هناك يكون البديل على مستوى المسار صادقًا: لا يوجد حقًّا ما يُعرَض بعد.

والاختبار سؤال واحد: هل في هذه الصفحة أي شيء أستطيع عرضه قبل وصول البيانات؟ إن كان الجواب نعم، فالحدّ في المكان الخطأ.

تفصيلان يكلّفان بعد ظهيرة كاملة

يسري loading.tsx على مقطعه وعلى كل مقطع تحته. فملفّ في app/loading.tsx هو بديل التطبيق بأكمله، وهذا ما لا يكاد يقصده أحد حين أنشأه وهو يعمل على مسار واحد.

وعلى البديل أن يحجز المساحة التي سيشغلها محتواه. فهيكل ارتفاعه 120 بكسل أمام رسم ارتفاعه 400 بكسل يعني إزاحة تخطيط بمقدار 280 بكسل لحظة وصول البيانات، ولا يعني CLS أن القفزة كانت من حالة التحميل الخاصة بك.

function ChartSkeleton() {
  // الارتفاع نفسه كالرسم، كي لا يتحرّك شيء عند التبديل.
  return <div className="h-[400px] animate-pulse rounded-xl bg-ink-100" />;
}

هذا كل شيء. loading.tsx تسهيلٌ لحالة واحدة، و<Suspense> هي الأداة لكل حالة أخرى - وهو ما يستحقّ معرفته قبل أن يتّخذ التسهيل القرار بالنيابة عنك.

العودة إلى كل المقالات