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

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

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

نظرة عامة

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

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

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

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

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

تخزين الطلبات مؤقتًا (Request Memoization)

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

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

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

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

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

رسم بياني يوضح كيفية عمل تخزين الطلبات مؤقتًا أثناء تصيير 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 من التصيير.

إعادة التحقق

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

عدم التخزين المؤقت

ينطبق التخزين المؤقت فقط على طريقة GET في طلبات fetch، ولا يتم تخزين الطرق الأخرى مثل POST وDELETE مؤقتًا. هذا السلوك الافتراضي هو تحسين من React ولا نوصي بعدم تخزينه مؤقتًا.

لإدارة الطلبات الفردية، يمكنك استخدام خاصية signal من AbortController. ومع ذلك، لن يؤدي هذا إلى عدم تخزين الطلبات مؤقتًا، بل سيؤدي إلى إلغاء الطلبات الجارية.

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

ذاكرة تخزين البيانات (Data Cache)

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

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

يمكنك استخدام خيارات cache وnext.revalidate لـ fetch لتكوين سلوك التخزين المؤقت.

كيف تعمل ذاكرة تخزين البيانات

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

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

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

المدة

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

إعادة التحقق

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

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

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

لإعادة التحقق من البيانات على فترات زمنية، يمكنك استخدام خيار 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 مرة أخرى، وسيتم جلب البيانات من مصدر البيانات الخارجي وتخزينها في ذاكرة تخزين البيانات.

عدم التخزين المؤقت

إذا كنت لا تريد تخزين الاستجابة من fetch مؤقتًا، يمكنك القيام بما يلي:

let data = await fetch('https://api.vercel.app/blog', { cache: 'no-store' })

ذاكرة تخزين المسار الكامل (Full Route Cache)

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

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

يقوم 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. التنقلات اللاحقة

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

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

التقديم الثابت والديناميكي

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

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

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

تعلم المزيد حول التقديم الثابت والديناميكي.

المدة

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

الإبطال

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

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

الانسحاب

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

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

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

يحتوي Next.js على ذاكرة تخزين مؤقت للموجه على جانب العميل في الذاكرة تقوم بتخزين حمولة RSC لقطع المسار، مقسمة حسب التخطيطات وحالات التحميل والصفحات.

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

مع ذاكرة التخزين المؤقت للموجه:

  • التخطيطات يتم تخزينها وإعادة استخدامها أثناء التنقل (التقديم الجزئي).
  • حالات التحميل يتم تخزينها وإعادة استخدامها أثناء التنقل لـتنقل فوري.
  • الصفحات لا يتم تخزينها افتراضيًا، ولكن يتم إعادة استخدامها أثناء التنقل للخلف والأمام في المتصفح. يمكنك تمكين التخزين المؤقت لقطع الصفحات باستخدام خيار التكوين التجريبي staleTimes.

من الجيد معرفة: هذه الذاكرة المؤقتة تنطبق تحديدًا على Next.js ومكونات الخادم، وتختلف عن bfcache للمتصفح، على الرغم من أن لها نتيجة مماثلة.

المدة

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

  • الجلسة: تظل الذاكرة المؤقتة عبر التنقل. ومع ذلك، يتم مسحها عند تحديث الصفحة.
  • فترة الإبطال التلقائي: يتم إبطال ذاكرة التخزين المؤقت للتخطيطات وحالات التحميل تلقائيًا بعد وقت محدد. تعتمد المدة على كيفية جلب المورد مسبقًا، وما إذا كان المورد قد تم توليده بشكل ثابت:
    • الجلب المسبق الافتراضي (prefetch={null} أو غير محدد): لا يتم تخزينه للصفحات الديناميكية، 5 دقائق للصفحات الثابتة.
    • الجلب المسبق الكامل (prefetch={true} أو router.prefetch): 5 دقائق لكل من الصفحات الثابتة والديناميكية.

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

من الجيد معرفة: يمكن استخدام خيار التكوين التجريبي staleTimes لضبط أوقات الإبطال التلقائي المذكورة أعلاه.

الإبطال

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

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

الانسحاب

اعتبارًا من Next.js 15، يتم الانسحاب من قطع الصفحات افتراضيًا.

من الجيد معرفة: يمكنك أيضًا الانسحاب من الجلب المسبق عن طريق تعيين خاصية prefetch لمكون <Link> إلى false.

تفاعلات التخزين المؤقت

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

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

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

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

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

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

يوضح الجدول التالي نظرة عامة حول كيفية تأثير واجهات برمجة التطبيقات المختلفة لـ 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, searchParamsانسحاب
generateStaticParamsتخزين مؤقت
React.cacheتخزين مؤقت
unstable_cacheتخزين مؤقت

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

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

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

router.prefetch

يمكن استخدام خيار prefetch لـ useRouter لجلب مسار مسبقًا يدويًا. هذا يضيف حمولة مكون خادم React إلى ذاكرة التخزين المؤقت للموجه.

راجع مرجع وصلة useRouter.

router.refresh

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

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

راجع مرجع وصلة useRouter.

fetch

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

سلوك التخزين المؤقت الافتراضي لـ fetch (على سبيل المثال، عندما لا يتم تحديد خيار cache) يساوي تعيين خيار cache إلى no-store:

let data = await fetch('https://api.vercel.app/blog', { cache: 'no-store' })

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

fetch options.cache

يمكنك اختيار تخزين fetch الفردي مؤقتًا عن طريق تعيين خيار cache إلى force-cache:

// اختيار التخزين المؤقت
fetch(`https://...`, { cache: 'force-cache' })

راجع مرجع واجهة برمجة التطبيقات لـ 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. معالجات المسار - لإعادة التحقق من البيانات استجابة لحدث طرف ثالث (مثل webhook). هذا لن يبطل ذاكرة التخزين المؤقت للموجه على الفور لأن معالج المسار غير مرتب بمسار محدد.
  2. إجراءات الخادم - لإعادة التحقق من البيانات بعد إجراء مستخدم (مثل تقديم نموذج). هذا سيبطل ذاكرة التخزين المؤقت للموجه للمسار المرتبط.

revalidatePath

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

revalidatePath('/')

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

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

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

revalidatePath مقابل router.refresh:

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

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

واجهات برمجة التطبيقات الديناميكية

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

cookies

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

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

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

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

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

  • const dynamic = 'force-dynamic'

سيؤدي خيار التكوين هذا إلى إلغاء اختيار جميع عمليات الجلب من ذاكرة التخزين المؤقت للبيانات (Data Cache) (أي no-store):

  • const fetchCache = 'default-no-store'

راجع fetchCache لمشاهدة خيارات أكثر تقدمًا.

راجع وثائق تكوين قطاع المسار لمزيد من الخيارات.

generateStaticParams

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

لتصيير جميع المسارات بشكل ثابت وقت البناء، قم بتوفير القائمة الكاملة للمسارات لـ generateStaticParams:

app/blog/[slug]/page.js
export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())

  return posts.map((post) => ({
    slug: post.slug,
  }))
}

لتصيير مجموعة فرعية من المسارات بشكل ثابت وقت البناء، والباقي عند زيارتها لأول مرة أثناء التشغيل، قم بإرجاع قائمة جزئية من المسارات:

app/blog/[slug]/page.js
export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())

  // تصيير أول 10 منشورات وقت البناء
  return posts.slice(0, 10).map((post) => ({
    slug: post.slug,
  }))
}

لتصيير جميع المسارات بشكل ثابت عند زيارتها لأول مرة، قم بإرجاع مصفوفة فارغة (لن يتم تصيير أي مسارات وقت البناء) أو استخدم export const dynamic = 'force-static':

app/blog/[slug]/page.js
export async function generateStaticParams() {
  return []
}

معلومة مفيدة: يجب عليك إرجاع مصفوفة من generateStaticParams، حتى لو كانت فارغة. وإلا، سيتم تصيير المسار بشكل ديناميكي.

app/changelog/[slug]/page.js
export const dynamic = 'force-static'

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

دالة cache في React

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

نظرًا لأن طلبات fetch يتم حفظها تلقائيًا، لا تحتاج إلى تغليفها في cache في React. ومع ذلك، يمكنك استخدام 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
})

On this page

نظرة عامةتخزين الطلبات مؤقتًا (Request Memoization)المدةإعادة التحققعدم التخزين المؤقتذاكرة تخزين البيانات (Data Cache)المدةإعادة التحققإعادة التحقق بناءً على الوقتإعادة التحقق عند الطلبعدم التخزين المؤقتذاكرة تخزين المسار الكامل (Full Route Cache)1. تصيير React على الخادم2. تخزين Next.js على الخادم (ذاكرة تخزين المسار الكامل)3. ترطيب React والمصالحة على العميل4. تخزين Next.js على العميل (ذاكرة تخزين الموجه)5. التنقلات اللاحقةالتقديم الثابت والديناميكيالمدةالإبطالالانسحابذاكرة التخزين المؤقت للموجه على جانب العميلالمدةالإبطالالانسحابتفاعلات التخزين المؤقتذاكرة التخزين المؤقت للبيانات وذاكرة التخزين المؤقت الكاملة للمسارذاكرة التخزين المؤقت للبيانات وذاكرة التخزين المؤقت للموجه على جانب العميلواجهات برمجة التطبيقات<Link>router.prefetchrouter.refreshfetchfetch options.cachefetch options.next.revalidatefetch options.next.tags و revalidateTagrevalidatePathواجهات برمجة التطبيقات الديناميكيةcookiesخيارات تكوين القطاع (Segment Config Options)generateStaticParamsدالة cache في React