التخزين المؤقت في Next.js

يحسن Next.js أداء تطبيقك ويقلل التكاليف من خلال تخزين أعمال التصيير وطلبات البيانات مؤقتًا. توفر هذه الصفحة نظرة متعمقة على آليات التخزين المؤقت في Next.js، وواجهات برمجة التطبيقات (APIs) التي يمكنك استخدامها لتكوينها، وكيفية تفاعلها مع بعضها البعض.

معلومة مفيدة: تساعدك هذه الصفحة على فهم كيفية عمل Next.js تحت الغطاء، لكنها ليست معرفة أساسية لتكون منتجًا باستخدام Next.js. يتم تحديد معظم استدلالات التخزين المؤقت في Next.js من خلال استخدامك لواجهات برمجة التطبيقات ولها إعدادات افتراضية لأفضل أداء مع تكوين صفري أو ضئيل.

نظرة عامة

إليك نظرة عامة عالية المستوى على آليات التخزين المؤقت المختلفة والغرض منها:

الآليةماذا تخزنأينالغرضالمدة
تخزين الطلبات مؤقتًاقيم الإرجاع للدوالالخادمإعادة استخدام البيانات في شجرة مكونات Reactدورة حياة الطلب الواحد
ذاكرة البيانات المؤقتةالبياناتالخادمتخزين البيانات عبر طلبات المستخدم والنشراتمستمر (يمكن إعادة التحقق منه)
ذاكرة المسار الكامل المؤقتةHTML وحمولة RSCالخادمتقليل تكلفة التصيير وتحسين الأداءمستمر (يمكن إعادة التحقق منه)
ذاكرة الموجه المؤقتةحمولة RSCالعميلتقليل طلبات الخادم أثناء التنقلجلسة المستخدم أو بناءً على الوقت

بشكل افتراضي، سيخزن Next.js أكبر قدر ممكن لتحسين الأداء وتقليل التكلفة. وهذا يعني أن المسارات تُصَيَّر بشكل ثابت وطلبات البيانات مخزنة مؤقتًا إلا إذا اخترت عدم ذلك. يوضح الرسم البياني أدناه سلوك التخزين المؤقت الافتراضي: عندما يتم تصيير مسار بشكل ثابت في وقت البناء وعند زيارة مسار ثابت لأول مرة.

رسم بياني يوضح سلوك التخزين المؤقت الافتراضي في Next.js للآليات الأربع، مع HIT وMISS وSET في وقت البناء وعند زيارة المسار لأول مرة.

يتغير سلوك التخزين المؤقت اعتمادًا على ما إذا كان المسار يُصَيَّر بشكل ثابت أو ديناميكي، وما إذا كانت البيانات مخزنة مؤقتًا أم لا، وما إذا كان الطلب جزءًا من زيارة أولية أو تنقل لاحق. اعتمادًا على حالة الاستخدام، يمكنك تكوين سلوك التخزين المؤقت للمسارات الفردية وطلبات البيانات.

تخزين الطلبات مؤقتًا

يمتد React لواجهة برمجة التطبيقات fetch لتخزين الطلبات التي لها نفس URL والخيارات تلقائيًا مؤقتًا. وهذا يعني أنه يمكنك استدعاء دالة fetch لنفس البيانات في أماكن متعددة في شجرة مكونات React مع تنفيذها مرة واحدة فقط.

طلبات Fetch المكررة

على سبيل المثال، إذا كنت بحاجة إلى استخدام نفس البيانات عبر مسار (مثل في Layout وصفحة ومكونات متعددة)، فلا يتعين عليك جلب البيانات في أعلى الشجرة ثم تمرير الخصائص بين المكونات. بدلاً من ذلك، يمكنك جلب البيانات في المكونات التي تحتاجها دون القلق بشأن الآثار المترتبة على الأداء لإنشاء طلبات متعددة عبر الشبكة لنفس البيانات.

async function getItem() {
  // يتم تخزين دالة `fetch` تلقائيًا مؤقتًا وتخزين النتيجة
  const res = await fetch('https://.../item/1')
  return res.json()
}

// يتم استدعاء هذه الدالة مرتين، ولكن يتم تنفيذها فقط في المرة الأولى
const item = await getItem() // cache MISS

// يمكن أن يكون الاستدعاء الثاني في أي مكان في مسارك
const item = await getItem() // cache HIT
async function getItem() {
  // يتم تخزين دالة `fetch` تلقائيًا مؤقتًا وتخزين النتيجة
  const res = await fetch('https://.../item/1')
  return res.json()
}

// يتم استدعاء هذه الدالة مرتين، ولكن يتم تنفيذها فقط في المرة الأولى
const item = await getItem() // cache MISS

// يمكن أن يكون الاستدعاء الثاني في أي مكان في مسارك
const item = await getItem() // cache HIT

كيف يعمل تخزين الطلبات مؤقتًا

رسم بياني يوضح كيفية عمل تخزين fetch مؤقتًا أثناء تصيير React.
  • أثناء تصيير مسار، في المرة الأولى التي يتم فيها استدعاء طلب معين، لن تكون نتيجته في الذاكرة وسيكون cache MISS.
  • لذلك، سيتم تنفيذ الدالة، وسيتم جلب البيانات من المصدر الخارجي، وسيتم تخزين النتيجة في الذاكرة.
  • سيؤدي استدعاء الدالة اللاحق لنفس الطلب في نفس تمرير التصيير إلى cache HIT، وسيتم إرجاع البيانات من الذاكرة دون تنفيذ الدالة.
  • بمجرد اكتمال تصيير المسار وتمرير التصيير، يتم "إعادة تعيين" الذاكرة ومسح جميع إدخالات تخزين الطلبات مؤقتًا.

معلومة مفيدة:

  • تخزين الطلبات مؤقتًا هو ميزة React وليست ميزة Next.js. تم تضمينها هنا لإظهار كيفية تفاعلها مع آليات التخزين المؤقت الأخرى.
  • ينطبق التخزين المؤقت فقط على طريقة GET في طلبات fetch.
  • ينطبق التخزين المؤقت فقط على شجرة مكونات React، وهذا يعني:
    • ينطبق على طلبات fetch في generateMetadata وgenerateStaticParams وLayouts وPages ومكونات الخادم الأخرى.
    • لا ينطبق على طلبات fetch في Route Handlers لأنها ليست جزءًا من شجرة مكونات React.
  • للحالات التي لا يكون فيها fetch مناسبًا (مثل بعض عملاء قواعد البيانات أو عملاء CMS أو عملاء GraphQL)، يمكنك استخدام دالة cache في React لتخزين الدوال مؤقتًا.

المدة

يستمر التخزين المؤقت طوال فترة حياة طلب الخادم حتى تنتهي شجرة مكونات React من التصيير.

إعادة التحقق

نظرًا لأن التخزين المؤقت غير مشترك عبر طلبات الخادم وينطبق فقط أثناء التصيير، فلا حاجة لإعادة التحقق منه.

عدم المشاركة

لعدم المشاركة في التخزين المؤقت لطلبات fetch، يمكنك تمرير signal من AbortController إلى الطلب.

app/example.js
const { signal } = new AbortController()
fetch(url, { signal })

ذاكرة البيانات المؤقتة

يحتوي Next.js على ذاكرة بيانات مدمجة تخزن نتائج جلب البيانات عبر طلبات الخادم الواردة والنشرات. وهذا ممكن لأن Next.js يمتد واجهة برمجة التطبيقات fetch الأصلية للسماح لكل طلب على الخادم بتعيين دلالات التخزين المؤقت الخاصة به.

معلومة مفيدة: في المتصفح، يشير خيار cache في fetch إلى كيفية تفاعل الطلب مع ذاكرة HTTP للمتصفح، في Next.js، يشير خيار cache إلى كيفية تفاعل طلب الخادم مع ذاكرة البيانات على الخادم.

بشكل افتراضي، يتم تخزين طلبات البيانات التي تستخدم fetch مؤقتًا. يمكنك استخدام خيارات cache وnext.revalidate في fetch لتكوين سلوك التخزين المؤقت.

كيف تعمل ذاكرة البيانات المؤقتة

رسم بياني يوضح كيفية تفاعل طلبات fetch المخزنة وغير المخزنة مؤقتًا مع ذاكرة البيانات المؤقتة. يتم تخزين الطلبات المخزنة مؤقتًا في ذاكرة البيانات المؤقتة وتخزينها مؤقتًا، بينما يتم جلب الطلبات غير المخزنة مؤقتًا من مصدر البيانات، ولا يتم تخزينها في ذاكرة البيانات المؤقتة، وتخزينها مؤقتًا.
  • في المرة الأولى التي يتم فيها استدعاء طلب fetch أثناء التصيير، يتحقق Next.js من ذاكرة البيانات المؤقتة للحصول على استجابة مخزنة مؤقتًا.
  • إذا تم العثور على استجابة مخزنة مؤقتًا، يتم إرجاعها على الفور وتخزينها مؤقتًا.
  • إذا لم يتم العثور على استجابة مخزنة مؤقتًا، يتم إجراء الطلب إلى مصدر البيانات، وتخزين النتيجة في ذاكرة البيانات المؤقتة، وتخزينها مؤقتًا.
  • بالنسبة للبيانات غير المخزنة مؤقتًا (مثل { cache: 'no-store' })، يتم دائمًا جلب النتيجة من مصدر البيانات، وتخزينها مؤقتًا.
  • سواء كانت البيانات مخزنة مؤقتًا أم لا، يتم دائمًا تخزين الطلبات مؤقتًا لتجنب إنشاء طلبات مكررة لنفس البيانات أثناء تمرير تصيير React.

الاختلافات بين ذاكرة البيانات المؤقتة وتخزين الطلبات مؤقتًا

بينما تساعد كلتا آليتي التخزين المؤقت في تحسين الأداء من خلال إعادة استخدام البيانات المخزنة مؤقتًا، فإن ذاكرة البيانات المؤقتة مستمرة عبر الطلبات الواردة والنشرات، بينما يستمر التخزين المؤقت فقط طوال فترة حياة الطلب.

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

المدة

ذاكرة البيانات المؤقتة مستمرة عبر الطلبات الواردة والنشرات ما لم تقم بإعادة التحقق أو عدم المشاركة.

إعادة التحقق

يمكن إعادة التحقق من البيانات المخزنة مؤقتًا بطريقتين، باستخدام:

  • إعادة التحقق بناءً على الوقت: إعادة التحقق من البيانات بعد مرور فترة زمنية معينة وإجراء طلب جديد. هذا مفيد للبيانات التي تتغير بشكل غير متكرر وليست الحداثة فيها بالغة الأهمية.
  • إعادة التحقق عند الطلب: إعادة التحقق من البيانات بناءً على حدث (مثل إرسال نموذج). يمكن أن تستخدم إعادة التحقق عند الطلب نهجًا يعتمد على العلامات أو المسار لإعادة التحقق من مجموعات البيانات دفعة واحدة. هذا مفيد عندما تريد التأكد من عرض أحدث البيانات في أسرع وقت ممكن (مثل عند تحديث المحتوى من نظام إدارة المحتوى الخاص بك).

إعادة التحقق بناءً على الوقت

لإعادة التحقق من البيانات على فترات زمنية، يمكنك استخدام خيار next.revalidate في fetch لتعيين عمر ذاكرة التخزين المؤقت للمورد (بالثواني).

// إعادة التحقق على الأكثر كل ساعة
fetch('https://...', { next: { revalidate: 3600 } })

بدلاً من ذلك، يمكنك استخدام خيارات تكوين قطاع المسار لتكوين جميع طلبات fetch في قطاع أو للحالات التي لا يمكنك فيها استخدام fetch.

كيف تعمل إعادة التحقق بناءً على الوقت

رسم بياني يوضح كيفية عمل إعادة التحقق بناءً على الوقت، بعد فترة إعادة التحقق، يتم إرجاع البيانات القديمة للطلب الأول، ثم يتم إعادة التحقق من البيانات.
  • في المرة الأولى التي يتم فيها استدعاء طلب fetch مع revalidate، سيتم جلب البيانات من مصدر البيانات الخارجي وتخزينها في ذاكرة البيانات المؤقتة.
  • أي طلبات يتم استدعاؤها خلال الإطار الزمني المحدد (مثل 60 ثانية) سترجع البيانات المخزنة مؤقتًا.
  • بعد الإطار الزمني، سيظل الطلب التالي يرجع البيانات المخزنة (القديمة الآن) مؤقتًا.
    • سيؤدي Next.js إلى إعادة التحقق من البيانات في الخلفية.
    • بمجرد جلب البيانات بنجاح، سيحدث Next.js ذاكرة البيانات المؤقتة بالبيانات الجديدة.
    • إذا فشلت إعادة التحقق في الخلفية، سيتم الاحتفاظ بالبيانات السابقة دون تغيير.

هذا مشابه لسلوك stale-while-revalidate.

إعادة التحقق عند الطلب

يمكن إعادة التحقق من البيانات عند الطلب عن طريق المسار (revalidatePath) أو عن طريق علامة ذاكرة التخزين المؤقت (revalidateTag).

كيف تعمل إعادة التحقق عند الطلب

رسم بياني يوضح كيفية عمل إعادة التحقق عند الطلب، يتم تحديث ذاكرة البيانات المؤقتة بالبيانات الجديدة بعد طلب إعادة التحقق.
  • في المرة الأولى التي يتم فيها استدعاء طلب fetch، سيتم جلب البيانات من مصدر البيانات الخارجي وتخزينها في ذاكرة البيانات المؤقتة.
  • عند تشغيل إعادة التحقق عند الطلب، سيتم مسح إدخالات ذاكرة التخزين المؤقت المناسبة من الذاكرة.
    • يختلف هذا عن إعادة التحقق بناءً على الوقت، التي تحتفظ بالبيانات القديمة في الذاكرة حتى يتم جلب البيانات الجديدة.
  • في المرة التالية التي يتم فيها إجراء طلب، سيكون مرة أخرى cache MISS، وسيتم جلب البيانات من مصدر البيانات الخارجي وتخزينها في ذاكرة البيانات المؤقتة.

عدم المشاركة

لطلبات جلب البيانات الفردية، يمكنك عدم المشاركة في التخزين المؤقت عن طريق تعيين خيار cache إلى no-store. وهذا يعني أنه سيتم جلب البيانات كلما تم استدعاء fetch.

// عدم المشاركة في التخزين المؤقت لطلب `fetch` فردي
fetch(`https://...`, { cache: 'no-store' })

بدلاً من ذلك، يمكنك أيضًا استخدام خيارات تكوين قطاع المسار لعدم المشاركة في التخزين المؤقت لقطاع مسار معين. سيؤثر هذا على جميع طلبات البيانات في قطاع المسار، بما في ذلك مكتبات الطرف الثالث.

// عدم المشاركة في التخزين المؤقت لجميع طلبات البيانات في قطاع المسار
export const dynamic = 'force-dynamic'

ذاكرة البيانات المؤقتة في Vercel

إذا تم نشر تطبيق Next.js الخاص بك على Vercel، نوصي بقراءة وثائق ذاكرة البيانات المؤقتة في Vercel لفهم أفضل للميزات الخاصة بـ Vercel.

ذاكرة المسار الكامل المؤقتة

مصطلحات ذات صلة:

قد ترى مصطلحات التحسين الثابت التلقائي أو توليد الموقع الثابت أو التصيير الثابت تُستخدم بالتبادل للإشارة إلى عملية تصيير وتخزين مسارات تطبيقك مؤقتًا في وقت البناء.

يُصَيِّر Next.js المسارات ويخزنها مؤقتًا تلقائيًا في وقت البناء. هذا تحسين يسمح لك بتقديم المسار المخزن مؤقتًا بدلاً من التصيير على الخادم لكل طلب، مما يؤدي إلى تحميل أسرع للصفحات.

لفهم كيفية عمل ذاكرة المسار الكامل المؤقتة، من المفيد النظر إلى كيفية تعامل React مع التصيير، وكيف يخزن Next.js النتيجة:

1. تصيير React على الخادم

على الخادم، يستخدم Next.js واجهات برمجة تطبيقات React لتنظيم التصيير. يتم تقسيم عمل التصيير إلى أجزاء: حسب أجزاء المسار الفردية وحدود Suspense.

يتم تصيير كل جزء في خطوتين:

  1. يُصَيِّر React مكونات الخادم إلى تنسيق بيانات خاص مُحَسَّن للبث، يُسمى حمولة مكون خادم React.
  2. يستخدم Next.js حمولة مكون خادم React وتعليمات JavaScript لمكون العميل لتصيير HTML على الخادم.

هذا يعني أنه لا يتعين علينا الانتظار حتى يتم تصيير كل شيء قبل تخزين العمل مؤقتًا أو إرسال استجابة. بدلاً من ذلك، يمكننا بث استجابة أثناء اكتمال العمل.

ما هي حمولة مكون خادم React؟

حمولة مكون خادم React هي تمثيل ثنائي مضغوط لشجرة مكونات خادم React المُصَيَّرة. يتم استخدامها بواسطة React على العميل لتحديث DOM للمتصفح. تحتوي حمولة مكون خادم React على:

  • نتيجة تصيير مكونات الخادم
  • عناصر نائبة لمكان تصيير مكونات العميل ومراجع لملفات JavaScript الخاصة بها
  • أي خصائص تم تمريرها من مكون خادم إلى مكون عميل

لمعرفة المزيد، راجع وثائق مكونات الخادم.

2. تخزين Next.js مؤقتًا على الخادم (ذاكرة المسار الكامل المؤقتة)

السلوك الافتراضي لذاكرة المسار الكامل المؤقتة، يوضح كيفية تخزين حمولة مكون خادم React وHTML مؤقتًا على الخادم للمسارات المصَيَّرة بشكل ثابت.

السلوك الافتراضي لـ Next.js هو تخزين نتيجة التصيير (حمولة مكون خادم React وHTML) لمسار على الخادم مؤقتًا. ينطبق هذا على المسارات المصَيَّرة بشكل ثابت في وقت البناء، أو أثناء إعادة التحقق.

3. ترطيب React والمصالحة على العميل

في وقت الطلب، على العميل:

  1. يتم استخدام HTML لعرض معاينة أولية سريعة غير تفاعلية لمكونات العميل والخادم.
  2. تُستخدم حمولة مكونات خادم React لمصالحة أشجار مكونات العميل والخادم المُصَيَّرة، وتحديث DOM.
  3. تُستخدم تعليمات JavaScript لترطيب مكونات العميل وجعل التطبيق تفاعليًا.

4. تخزين Next.js مؤقتًا على العميل (ذاكرة الموجه المؤقتة)

يتم تخزين حمولة مكون خادم React في ذاكرة الموجه المؤقتة على جانب العميل - وهي ذاكرة تخزين مؤقت في الذاكرة، مقسمة حسب أجزاء المسار الفردية. تُستخدم ذاكرة الموجه المؤقتة لتحسين تجربة التنقل عن طريق تخزين المسارات التي تمت زيارتها مسبقًا وجلب المسارات المستقبلية مسبقًا.

5. التنقلات اللاحقة

في التنقلات اللاحقة أو أثناء الجلب المسبق (prefetching)، سيتحقق Next.js مما إذا كان حمولة مكونات الخادم (React Server Components Payload) مخزنة في ذاكرة التوجيه (Router Cache). إذا كانت موجودة، فسيتم تخطي إرسال طلب جديد إلى الخادم.

إذا لم تكن أجزاء المسار موجودة في الذاكرة المؤقتة، سيقوم Next.js بجلب حمولة مكونات الخادم من الخادم، وملء ذاكرة التوجيه على العميل.

العرض الثابت والديناميكي

ما إذا كان المسار مخزناً مؤقتاً أثناء البناء أم لا يعتمد على ما إذا كان يتم عرضه بشكل ثابت أو ديناميكي. يتم تخزين المسارات الثابتة مؤقتاً افتراضياً، بينما يتم عرض المسارات الديناميكية وقت الطلب ولا يتم تخزينها مؤقتاً.

يوضح هذا الرسم البياني الفرق بين المسارات المعروضة بشكل ثابت وديناميكي، مع البيانات المخزنة وغير المخزنة مؤقتاً:

كيف يؤثر العرض الثابت والديناميكي على ذاكرة المسار الكاملة (Full Route Cache). يتم تخزين المسارات الثابتة مؤقتاً أثناء البناء أو بعد إعادة التحقق من البيانات، بينما لا يتم تخزين المسارات الديناميكية مؤقتاً أبداً

تعرف على المزيد حول العرض الثابت والديناميكي.

المدة الزمنية

افتراضياً، تكون ذاكرة المسار الكاملة (Full Route Cache) دائمة. وهذا يعني أن ناتج العرض يتم تخزينه مؤقتاً عبر طلبات المستخدمين.

إبطال الصلاحية

هناك طريقتان يمكنك من خلالهما إبطال صلاحية ذاكرة المسار الكاملة:

  • إعادة التحقق من البيانات: إعادة التحقق من ذاكرة البيانات (Data Cache) سيقوم بدوره بإبطال صلاحية ذاكرة التوجيه (Router Cache) عن طريق إعادة عرض المكونات على الخادم وتخزين ناتج العرض الجديد مؤقتاً.
  • إعادة النشر: على عكس ذاكرة البيانات التي تظل عبر عمليات النشر، يتم مسح ذاكرة المسار الكاملة عند عمليات النشر الجديدة.

الانسحاب

يمكنك الانسحاب من ذاكرة المسار الكاملة، أو بعبارة أخرى، عرض المكونات ديناميكياً لكل طلب وارد، عن طريق:

  • استخدام وظيفة ديناميكية (Dynamic Function): سيؤدي هذا إلى إخراج المسار من ذاكرة المسار الكاملة وعرضه ديناميكياً وقت الطلب. لا يزال يمكن استخدام ذاكرة البيانات.
  • استخدام خيارات تكوين جزء المسار dynamic = 'force-dynamic' أو revalidate = 0: سيؤدي هذا إلى تخطي ذاكرة المسار الكاملة وذاكرة البيانات. مما يعني أنه سيتم عرض المكونات وجلب البيانات في كل طلب وارد إلى الخادم. ستظل ذاكرة التوجيه سارية لأنها ذاكرة على جانب العميل.
  • الانسحاب من ذاكرة البيانات (Data Cache): إذا كان للمسار طلب fetch غير مخزن مؤقتاً، فسيؤدي هذا إلى إخراج المسار من ذاكرة المسار الكاملة. سيتم جلب البيانات لطلب fetch المحدد لكل طلب وارد. ستظل طلبات fetch الأخرى التي لا تنسحب من التخزين المؤقت مخزنة في ذاكرة البيانات. وهذا يسمح بمزيج من البيانات المخزنة وغير المخزنة مؤقتاً.

ذاكرة التوجيه (Router Cache)

المصطلحات ذات الصلة:

قد تشاهد الإشارة إلى ذاكرة التوجيه باسم ذاكرة جانب العميل (Client-side Cache) أو ذاكرة الجلب المسبق (Prefetch Cache). بينما تشير ذاكرة الجلب المسبق إلى أجزاء المسار التي تم جلبها مسبقاً، تشير ذاكرة جانب العميل إلى ذاكرة التوجيه بأكملها، والتي تشمل كلاً من الأجزاء التي تمت زيارتها والتي تم جلبها مسبقاً. هذه الذاكرة المؤقتة تنطبق تحديداً على Next.js ومكونات الخادم، وهي مختلفة عن bfcache المتصفح، على الرغم من أن لها نتيجة مماثلة.

يمتلك Next.js ذاكرة مؤقتة على جانب العميل في الذاكرة تقوم بتخزين حمولة مكونات الخادم (React Server Component Payload)، مقسمة حسب أجزاء المسار الفردية، طوال مدة جلسة المستخدم. وهذا ما يسمى بذاكرة التوجيه (Router Cache).

كيف تعمل ذاكرة التوجيه

كيف تعمل ذاكرة التوجيه للمسارات الثابتة والديناميكية، مع عرض MISS و HIT للتنقلات الأولية واللاحقة.

عندما يتنقل المستخدمون بين المسارات، يقوم Next.js بتخزين أجزاء المسار التي تمت زيارتها ويجلب مسبقاً المسارات التي من المحتمل أن يتنقل إليها المستخدم (بناءً على مكونات <Link> في نطاق الرؤية لديهم).

ينتج عن هذا تحسين تجربة التنقل للمستخدم:

  • تنقل فوري للخلف/الأمام لأن المسارات التي تمت زيارتها مخزنة مؤقتاً وتنقل سريع إلى المسارات الجديدة بسبب الجلب المسبق والعرض الجزئي (Partial Rendering).
  • لا يوجد إعادة تحميل كاملة للصفحة بين التنقلات ويتم الحفاظ على حالة React وحالة المتصفح.

الفرق بين ذاكرة التوجيه وذاكرة المسار الكاملة:

تقوم ذاكرة التوجيه بتخزين حمولة مكونات الخادم (React Server Component Payload) مؤقتاً في المتصفح طوال مدة جلسة المستخدم، بينما تقوم ذاكرة المسار الكاملة بتخزين حمولة مكونات الخادم وHTML بشكل دائم على الخادم عبر طلبات متعددة للمستخدمين.

بينما تقوم ذاكرة المسار الكاملة بتخزين المسارات المعروضة بشكل ثابت فقط، تنطبق ذاكرة التوجيه على كل من المسارات المعروضة بشكل ثابت وديناميكي.

المدة الزمنية

يتم تخزين الذاكرة المؤقتة في الذاكرة المؤقتة للمتصفح. هناك عاملان يحددان المدة التي تستمر فيها ذاكرة التوجيه:

  • الجلسة: تظل الذاكرة المؤقتة عبر التنقل. ومع ذلك، يتم مسحها عند تحديث الصفحة.
  • فترة الإبطال التلقائي: يتم إبطال صلاحية ذاكرة جزء فردي تلقائياً بعد وقت محدد. تعتمد المدة على ما إذا كان المسار معروضاً بشكل ثابت أو ديناميكي:
    • المعروض ديناميكياً: 30 ثانية
    • المعروض ثابتاً: 5 دقائق

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

عن طريق إضافة prefetch={true} أو استدعاء router.prefetch لمسار معروض ديناميكياً، يمكنك اختيار التخزين المؤقت لمدة 5 دقائق.

إبطال الصلاحية

هناك طريقتان يمكنك من خلالهما إبطال صلاحية ذاكرة التوجيه:

  • في إجراء خادم (Server Action):
    • إعادة التحقق من البيانات حسب الطلب عن طريق المسار باستخدام (revalidatePath) أو عن طريق علامة الذاكرة المؤقتة باستخدام (revalidateTag)
    • يؤدي استخدام cookies.set أو cookies.delete إلى إبطال صلاحية ذاكرة التوجيه لمنع المسارات التي تستخدم ملفات تعريف الارتباط من أن تصبح قديمة (مثل المصادقة).
  • يؤدي استدعاء router.refresh إلى إبطال صلاحية ذاكرة التوجيه وإجراء طلب جديد إلى الخادم للمسار الحالي.

الانسحاب

لا يمكن الانسحاب من ذاكرة التوجيه.

يمكنك الانسحاب من الجلب المسبق عن طريق تعيين خاصية prefetch لمكون <Link> على false. ومع ذلك، سيظل هذا يقوم بتخزين أجزاء المسار مؤقتاً لمدة 30 ثانية للسماح بالتنقل الفوري بين الأجزاء المتداخلة، مثل أشرطة التبويب، أو التنقل للخلف والأمام. ستظل المسارات التي تمت زيارتها مخزنة مؤقتاً.

تفاعلات الذاكرة المؤقتة

عند تكوين آليات التخزين المؤقت المختلفة، من المهم فهم كيفية تفاعلها مع بعضها البعض:

ذاكرة البيانات وذاكرة المسار الكاملة

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

ذاكرة البيانات وذاكرة التوجيه على جانب العميل

  • إعادة التحقق من ذاكرة البيانات في معالج المسار (Route Handler) لن يبطل صلاحية ذاكرة التوجيه على الفور لأن معالج المسار غير مرتبط بمسار محدد. هذا يعني أن ذاكرة التوجيه ستستمر في تقديم الحمولة السابقة حتى تحديث قوي، أو انتهاء فترة الإبطال التلقائي.
  • لإبطال صلاحية ذاكرة البيانات وذاكرة التوجيه على الفور، يمكنك استخدام revalidatePath أو revalidateTag في إجراء خادم (Server Action).

واجهات برمجة التطبيقات (APIs)

يوضح الجدول التالي نظرة عامة على كيفية تأثير واجهات برمجة التطبيقات المختلفة لـ Next.js على التخزين المؤقت:

الواجهة البرمجيةذاكرة التوجيهذاكرة المسار الكاملةذاكرة البياناتذاكرة React
<Link prefetch>تخزين مؤقت
router.prefetchتخزين مؤقت
router.refreshإعادة التحقق
fetchتخزين مؤقتتخزين مؤقت
fetch options.cacheتخزين مؤقت أو انسحاب
fetch options.next.revalidateإعادة التحققإعادة التحقق
fetch options.next.tagsتخزين مؤقتتخزين مؤقت
revalidateTagإعادة التحقق (إجراء خادم)إعادة التحققإعادة التحقق
revalidatePathإعادة التحقق (إجراء خادم)إعادة التحققإعادة التحقق
const revalidateإعادة التحقق أو انسحابإعادة التحقق أو انسحاب
const dynamicتخزين مؤقت أو انسحابتخزين مؤقت أو انسحاب
cookiesإعادة التحقق (إجراء خادم)انسحاب
headers, useSearchParams, searchParamsانسحاب
generateStaticParamsتخزين مؤقت
React.cacheتخزين مؤقت
unstable_cache (قريباً)

افتراضياً، يقوم مكون <Link> تلقائياً بجلب المسارات مسبقاً من ذاكرة المسار الكاملة وإضافة حمولة مكونات الخادم (React Server Component Payload) إلى ذاكرة التوجيه.

لتعطيل الجلب المسبق، يمكنك تعيين خاصية prefetch على false. ولكن هذا لن يتخطى التخزين المؤقت بشكل دائم، سيظل جزء المسار مخزناً مؤقتاً على جانب العميل عندما يزور المستخدم المسار.

تعرف على المزيد حول مكون <Link>.

router.prefetch

يمكن استخدام خيار prefetch في خطاف useRouter لجلب مسار مسبقاً يدوياً. هذا يضيف حمولة مكونات الخادم (React Server Component Payload) إلى ذاكرة التوجيه.

راجع مرجع واجهة برمجة التطبيقات لـخطاف useRouter.

router.refresh

يمكن استخدام خيار refresh في خطاف useRouter لتحديث مسار يدوياً. هذا يمسح ذاكرة التوجيه بالكامل، ويجعل طلباً جديداً إلى الخادم للمسار الحالي. لا يؤثر refresh على ذاكرة البيانات أو ذاكرة المسار الكاملة.

سيتم التوفيق بين نتيجة العرض على العميل مع الحفاظ على حالة React وحالة المتصفح.

راجع مرجع واجهة برمجة التطبيقات لـخطاف useRouter.

fetch

يتم تخزين البيانات التي يتم إرجاعها من fetch تلقائياً في ذاكرة البيانات.

// مخزن مؤقت افتراضياً. `force-cache` هو الخيار الافتراضي ويمكن حذفه.
fetch(`https://...`, { cache: 'force-cache' })

راجع مرجع واجهة برمجة التطبيقات لـ fetch لمزيد من الخيارات.

fetch options.cache

يمكنك الانسحاب من تخزين بيانات طلبات fetch الفردية عن طريق تعيين خيار cache على no-store:

// الانسحاب من التخزين المؤقت
fetch(`https://...`, { cache: 'no-store' })

نظراً لأن ناتج العرض يعتمد على البيانات، فإن استخدام cache: 'no-store' سيتخطى أيضاً ذاكرة المسار الكاملة للمسار حيث يتم استخدام طلب fetch. أي أن المسار سيتم عرضه ديناميكياً في كل طلب، ولكن يمكنك الحصول على طلبات بيانات أخرى مخزنة مؤقتاً في نفس المسار.

راجع مرجع واجهة برمجة التطبيقات لـ fetch لمزيد من الخيارات.

fetch options.next.revalidate

يمكنك استخدام خيار next.revalidate لـ fetch لتعيين فترة إعادة التحقق (بالثواني) لطلب fetch فردي. سيؤدي هذا إلى إعادة التحقق من ذاكرة البيانات، والتي بدورها ستقوم بإعادة التحقق من ذاكرة المسار الكاملة. سيتم جلب بيانات جديدة، وسيتم إعادة عرض المكونات على الخادم.

// إعادة التحقق على الأكثر بعد ساعة واحدة
fetch(`https://...`, { next: { revalidate: 3600 } })

راجع مرجع واجهة برمجة التطبيقات لـ fetch لمزيد من الخيارات.

fetch options.next.tags و revalidateTag

يمتلك Next.js نظام وضع علامات على الذاكرة المؤقتة للتخزين المؤقت الدقيق للبيانات وإعادة التحقق منها.

  1. عند استخدام fetch أو unstable_cache، لديك خيار وضع علامات على إدخالات الذاكرة المؤقتة بواحدة أو أكثر من العلامات.
  2. ثم يمكنك استدعاء revalidateTag لمسح إدخالات الذاكرة المؤقتة المرتبطة بهذه العلامة.

على سبيل المثال، يمكنك تعيين علامة عند جلب البيانات:

// تخزين البيانات مع علامة
fetch(`https://...`, { next: { tags: ['a', 'b', 'c'] } })

ثم استدعاء revalidateTag مع علامة لمسح إدخال الذاكرة المؤقتة:

// إعادة التحقق من الإدخالات بعلامة محددة
revalidateTag('a')

هناك مكانان يمكنك استخدام revalidateTag فيهما، اعتماداً على ما تحاول تحقيقه:

  1. معالجات المسار (Route Handlers) - لإعادة التحقق من البيانات استجابةً لحدث طرف ثالث (مثل webhook). هذا لن يبطل صلاحية ذاكرة التوجيه على الفور لأن معالج المسار غير مرتبط بمسار محدد.
  2. إجراءات الخادم (Server Actions) - لإعادة التحقق من البيانات بعد إجراء المستخدم (مثل تقديم نموذج). هذا سيبطل صلاحية ذاكرة التوجيه للمسار المرتبط.

revalidatePath

تتيح لك revalidatePath إعادة التحقق يدويًا من البيانات و إعادة عرض مقاطع المسار أسفل مسار معين في عملية واحدة. يؤدي استدعاء طرق revalidatePath إلى إعادة التحقق من ذاكرة التخزين المؤقت للبيانات (Data Cache)، مما يؤدي بدوره إلى إبطال ذاكرة التخزين المؤقت الكاملة للمسار (Full Route Cache).

revalidatePath('/')

هناك مكانان يمكنك استخدام revalidatePath فيهما، اعتمادًا على ما تحاول تحقيقه:

  1. معالجات المسار (Route Handlers) - لإعادة التحقق من البيانات استجابةً لحدث طرف ثالث (مثل webhook).
  2. إجراءات الخادم (Server Actions) - لإعادة التحقق من البيانات بعد تفاعل المستخدم (مثل تقديم نموذج، النقر على زر).

راجع مرجع واجهة برمجة التطبيقات لـ revalidatePath لمزيد من المعلومات.

revalidatePath مقابل router.refresh:

يؤدي استدعاء router.refresh إلى مسح ذاكرة التخزين المؤقت للموجه (Router cache)، وإعادة عرض مقاطع المسار على الخادم دون إبطال ذاكرة التخزين المؤقت للبيانات (Data Cache) أو ذاكرة التخزين المؤقت الكاملة للمسار (Full Route Cache).

الفرق هو أن revalidatePath تفرغ ذاكرة التخزين المؤقت للبيانات وذاكرة التخزين المؤقت الكاملة للمسار، بينما router.refresh() لا تغير ذاكرة التخزين المؤقت للبيانات وذاكرة التخزين المؤقت الكاملة للمسار، لأنها واجهة برمجة تطبيقات من جانب العميل.

الدوال الديناميكية (Dynamic Functions)

cookies، headers، useSearchParams، و searchParams هي دوال ديناميكية تعتمد على معلومات الطلب الواردة أثناء التشغيل. استخدامها سيؤدي إلى استبعاد المسار من ذاكرة التخزين المؤقت الكاملة للمسار (Full Route Cache)، بمعنى آخر، سيتم عرض المسار ديناميكيًا.

cookies

استخدام cookies.set أو cookies.delete في إجراء خادم (Server Action) يبطل ذاكرة التخزين المؤقت للموجه (Router Cache) لمنع المسارات التي تستخدم ملفات تعريف الارتباط (cookies) من أن تصبح قديمة (على سبيل المثال، لتعكس تغييرات المصادقة).

راجع مرجع واجهة برمجة التطبيقات لـ cookies.

خيارات تكوين المقطع (Segment Config Options)

يمكن استخدام خيارات تكوين مقطع المسار (Route Segment Config) لتجاوز الإعدادات الافتراضية لمقطع المسار أو عندما لا تتمكن من استخدام واجهة برمجة التطبيقات fetch (على سبيل المثال، عميل قاعدة بيانات أو مكتبات طرف ثالث).

ستؤدي خيارات تكوين مقطع المسار التالية إلى استبعاد ذاكرة التخزين المؤقت للبيانات (Data Cache) وذاكرة التخزين المؤقت الكاملة للمسار (Full Route Cache):

  • const dynamic = 'force-dynamic'
  • const revalidate = 0

راجع توثيق تكوين مقطع المسار (Route Segment Config) لمزيد من الخيارات.

generateStaticParams

بالنسبة للمقاطع الديناميكية (dynamic segments) (على سبيل المثال app/blog/[slug]/page.js)، يتم تخزين المسارات المقدمة من generateStaticParams في ذاكرة التخزين المؤقت الكاملة للمسار (Full Route Cache) أثناء وقت البناء. في وقت الطلب، سيخزن Next.js أيضًا المسارات التي لم تكن معروفة في وقت البناء عند زيارتها لأول مرة.

يمكنك تعطيل التخزين المؤقت في وقت الطلب باستخدام خيار export const dynamicParams = false في مقطع المسار. عند استخدام خيار التكوين هذا، سيتم تقديم المسارات المقدمة من generateStaticParams فقط، وستؤدي المسارات الأخرى إلى خطأ 404 أو تطابق (في حالة المسارات الشاملة (catch-all routes)).

راجع مرجع واجهة برمجة التطبيقات لـ generateStaticParams.

دالة React cache

تتيح لك دالة React cache تخزين القيمة المرجعة للدالة مؤقتًا، مما يسمح لك باستدعاء نفس الدالة عدة مرات مع تنفيذها مرة واحدة فقط.

نظرًا لأن طلبات fetch يتم تخزينها مؤقتًا تلقائيًا، فلا تحتاج إلى تغليفها في React cache. ومع ذلك، يمكنك استخدام cache لتخزين طلبات البيانات يدويًا للحالات التي لا تكون فيها واجهة برمجة التطبيقات fetch مناسبة. على سبيل المثال، بعض عملاء قواعد البيانات، أو عملاء نظام إدارة المحتوى (CMS)، أو عملاء GraphQL.

import { cache } from 'react'
import db from '@/lib/db'

export const getItem = cache(async (id: string) => {
  const item = await db.item.findUnique({ id })
  return item
})
import { cache } from 'react'
import db from '@/lib/db'

export const getItem = cache(async (id) => {
  const item = await db.item.findUnique({ id })
  return item
})

unstable_cache

unstable_cache هي واجهة برمجة تطبيقات تجريبية لإضافة قيم إلى ذاكرة التخزين المؤقت للبيانات (Data Cache) عندما لا تكون واجهة برمجة التطبيقات fetch مناسبة. على سبيل المثال، عند استخدام عملاء قواعد البيانات، أو عملاء نظام إدارة المحتوى (CMS)، أو GraphQL.

import { unstable_cache } from 'next/cache'

export default async function Page() {
  const cachedData = await unstable_cache(
    async () => {
      const data = await db.query('...')
      return data
    },
    ['cache-key'],
    {
      tags: ['a', 'b', 'c'],
      revalidate: 10,
    }
  )()
}

تحذير: هذه الواجهة قيد التطوير، ولا نوصي باستخدامها في الإنتاج. تم سردها هنا لإظهار الاتجاه المستقبلي لـ ذاكرة التخزين المؤقت للبيانات (Data Cache).