التحميل المتأخر (Lazy Loading)

يساعد التحميل المتأخر في Next.js على تحسين أداء التحميل الأولي للتطبيق عن طريق تقليل كمية JavaScript المطلوبة لعرض مسار.

يسمح لك بتأجيل تحميل مكونات العميل (Client Components) والمكتبات المستوردة، وإدراجها في حزمة العميل فقط عند الحاجة إليها. على سبيل المثال، قد ترغب في تأجيل تحميل نافذة مشروطة حتى ينقر المستخدم لفتحها.

هناك طريقتان لتنفيذ التحميل المتأخر في Next.js:

  1. استخدام الاستيراد الديناميكي مع next/dynamic
  2. استخدام React.lazy() مع Suspense

بشكل افتراضي، يتم تقسيم الشفرة (Code Splitting) تلقائيًا لمكونات الخادم (Server Components)، ويمكنك استخدام البث (Streaming) لإرسال أجزاء واجهة المستخدم تدريجيًا من الخادم إلى العميل. ينطبق التحميل المتأخر على مكونات العميل.

next/dynamic

next/dynamic هو مزيج من React.lazy() و Suspense. يعمل بنفس الطريقة في كل من دليل app و pages للسماح بالهجرة التدريجية.

أمثلة

باستخدام next/dynamic، لن يتم تضمين مكون الرأس في حزمة JavaScript الأولية للصفحة. ستقوم الصفحة بعرض fallback الخاص بـ Suspense أولاً، ثم مكون Header عند حل حدود Suspense.

import dynamic from 'next/dynamic'

const DynamicHeader = dynamic(() => import('../components/header'), {
  loading: () => <p>جار التحميل...</p>,
})

export default function Home() {
  return <DynamicHeader />
}

ملاحظة مهمة: في import('مسار/إلى/المكون')، يجب كتابة المسار بشكل صريح. لا يمكن أن يكون سلسلة قالب ولا متغيرًا. بالإضافة إلى ذلك، يجب أن تكون import() داخل استدعاء dynamic() لكي يتمكن Next.js من مطابقة حزم webpack / معرّفات الوحدات مع استدعاء dynamic() المحدد وتحميلها مسبقًا قبل العرض. لا يمكن استخدام dynamic() داخل عرض React لأنه يجب وضع علامة عليها في المستوى الأعلى للوحدة لكي يعمل التحميل المسبق، مشابهًا لـ React.lazy.

مع التصديرات المسماة

لاستيراد تصدير مسماة ديناميكيًا، يمكنك إعادته من الـ Promise الذي تُرجعه import():

components/hello.js
export function Hello() {
  return <p>مرحبًا!</p>
}

// pages/index.js
import dynamic from 'next/dynamic'

const DynamicComponent = dynamic(() =>
  import('../components/hello').then((mod) => mod.Hello)
)

بدون عرض من جانب الخادم (SSR)

لتحميل مكون ديناميكيًا على جانب العميل فقط، يمكنك استخدام خيار ssr لتعطيل العرض من جانب الخادم. هذا مفيد إذا كانت تبعية خارجية أو مكون يعتمد على واجهات برمجة المتصفح مثل window.

import dynamic from 'next/dynamic'

const DynamicHeader = dynamic(() => import('../components/header'), {
  ssr: false,
})

مع المكتبات الخارجية

هذا المثال يستخدم المكتبة الخارجية fuse.js للبحث الضبابي. يتم تحميل الوحدة فقط في المتصفح بعد إدخال المستخدم في حقل البحث.

import { useState } from 'react'

const names = ['Tim', 'Joe', 'Bel', 'Lee']

export default function Page() {
  const [results, setResults] = useState()

  return (
    <div>
      <input
        type="text"
        placeholder="Search"
        onChange={async (e) => {
          const { value } = e.currentTarget
          // تحميل fuse.js ديناميكيًا
          const Fuse = (await import('fuse.js')).default
          const fuse = new Fuse(names)

          setResults(fuse.search(value))
        }}
      />
      <pre>Results: {JSON.stringify(results, null, 2)}</pre>
    </div>
  )
}