التحميل المتأخر (Lazy Loading)
يساعد التحميل المتأخر في Next.js على تحسين أداء التحميل الأولي للتطبيق عن طريق تقليل كمية JavaScript المطلوبة لعرض مسار.
يسمح لك بتأجيل تحميل مكونات العميل (Client Components) والمكتبات المستوردة، وإدراجها في حزمة العميل فقط عند الحاجة إليها. على سبيل المثال، قد ترغب في تأجيل تحميل نافذة مشروطة حتى ينقر المستخدم لفتحها.
هناك طريقتان لتنفيذ التحميل المتأخر في Next.js:
- استخدام الاستيراد الديناميكي مع
next/dynamic
- استخدام
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()
:
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>
)
}