جلب البيانات، التخزين المؤقت، وإعادة التحقق
يعد جلب البيانات جزءًا أساسيًا من أي تطبيق. تتناول هذه الصفحة كيفية جلب البيانات، تخزينها مؤقتًا، وإعادة التحقق منها في React وNext.js.
هناك أربع طرق لجلب البيانات:
- على الخادم باستخدام
fetch
- على الخادم باستخدام مكتبات الطرف الثالث
- على العميل عبر Route Handler
- على العميل باستخدام مكتبات الطرف الثالث.
جلب البيانات على الخادم باستخدام fetch
يمتد Next.js واجهة برمجة تطبيقات fetch
الأصلية للسماح لك بتكوين سلوك التخزين المؤقت وإعادة التحقق لكل طلب جلب على الخادم. يمتد React fetch
لتلقائيًا تذكر طلبات الجلب أثناء عرض شجرة مكونات React.
يمكنك استخدام fetch
مع async
/await
في مكونات الخادم، في Route Handlers، وفي Server Actions.
على سبيل المثال:
async function getData() {
const res = await fetch('https://api.example.com/...')
// القيمة المرجعة *ليست* متسلسلة
// يمكنك إرجاع Date، Map، Set، إلخ.
if (!res.ok) {
// سيؤدي هذا إلى تنشيط أقرب حد خطأ `error.js`
throw new Error('فشل في جلب البيانات')
}
return res.json()
}
export default async function Page() {
const data = await getData()
return <main></main>
}
async function getData() {
const res = await fetch('https://api.example.com/...')
// القيمة المرجعة *ليست* متسلسلة
// يمكنك إرجاع Date، Map، Set، إلخ.
if (!res.ok) {
// سيؤدي هذا إلى تنشيط أقرب حد خطأ `error.js`
throw new Error('فشل في جلب البيانات')
}
return res.json()
}
export default async function Page() {
const data = await getData()
return <main></main>
}
معلومة مفيدة:
- يوفر Next.js دوال مساعدة قد تحتاجها عند جلب البيانات في مكونات الخادم مثل
cookies
وheaders
. سيؤدي هذا إلى عرض المسار ديناميكيًا حيث تعتمد على معلومات وقت الطلب.- في Route Handlers، لا يتم تذكر طلبات
fetch
حيث أن Route Handlers ليست جزءًا من شجرة مكونات React.- لاستخدام
async
/await
في مكون خادم مع TypeScript، ستحتاج إلى استخدام TypeScript5.1.3
أو أعلى و@types/react
18.2.8
أو أعلى.
التخزين المؤقت للبيانات
يخزن التخزين المؤقت البيانات حتى لا تحتاج إلى إعادة جلبها من مصدر البيانات في كل طلب.
افتراضيًا، يقوم Next.js تلقائيًا بتخزين القيم المرجعة من fetch
في ذاكرة التخزين المؤقت للبيانات على الخادم. هذا يعني أنه يمكن جلب البيانات في وقت البناء أو وقت الطلب، تخزينها مؤقتًا، وإعادة استخدامها في كل طلب بيانات.
// 'force-cache' هو الافتراضي، ويمكن حذفه
fetch('https://...', { cache: 'force-cache' })
يتم أيضًا تخزين طلبات fetch
التي تستخدم طريقة POST
تلقائيًا. ما لم تكن داخل Route Handler تستخدم طريقة POST
، فلن يتم تخزينها مؤقتًا.
ما هي ذاكرة التخزين المؤقت للبيانات؟
ذاكرة التخزين المؤقت للبيانات هي ذاكرة تخزين مؤقت HTTP دائمة. اعتمادًا على منصتك، يمكن أن تتوسع الذاكرة المؤقتة تلقائيًا وتكون مشتركة عبر مناطق متعددة.
تعلم المزيد عن ذاكرة التخزين المؤقت للبيانات.
إعادة التحقق من البيانات
إعادة التحقق هي عملية مسح ذاكرة التخزين المؤقت للبيانات وإعادة جلب أحدث البيانات. هذا مفيد عندما تتغير بياناتك وتريد التأكد من عرض أحدث المعلومات.
يمكن إعادة التحقق من البيانات المخزنة مؤقتًا بطريقتين:
- إعادة التحقق المبنية على الوقت: إعادة التحقق من البيانات تلقائيًا بعد مرور فترة زمنية معينة. هذا مفيد للبيانات التي تتغير بشكل غير متكرر ولا تكون الحداثة حرجة.
- إعادة التحقق عند الطلب: إعادة التحقق من البيانات يدويًا بناءً على حدث (مثل إرسال نموذج). يمكن استخدام إعادة التحقق عند الطلب نهجًا يعتمد على العلامات أو المسارات لإعادة التحقق من مجموعات البيانات دفعة واحدة. هذا مفيد عندما تريد التأكد من عرض أحدث البيانات في أسرع وقت ممكن (مثل عند تحديث المحتوى من نظام إدارة المحتوى الخاص بك).
إعادة التحقق المبنية على الوقت
لإعادة التحقق من البيانات على فترات زمنية، يمكنك استخدام خيار next.revalidate
في fetch
لتعيين عمر ذاكرة التخزين المؤقت للمورد (بالثواني).
fetch('https://...', { next: { revalidate: 3600 } })
بدلاً من ذلك، لإعادة التحقق من جميع طلبات fetch
في مقطع مسار، يمكنك استخدام خيارات تكوين المقطع.
export const revalidate = 3600 // إعادة التحقق على الأكثر كل ساعة
إذا كان لديك عدة طلبات جلب في مسار معروض بشكل ثابت، ولكل منها تردد إعادة تحقق مختلف. سيتم استخدام أقل وقت لجميع الطلبات. بالنسبة للمسارات المعروضة ديناميكيًا، سيتم إعادة التحقق من كل طلب fetch
بشكل مستقل.
تعلم المزيد عن إعادة التحقق المبنية على الوقت.
إعادة التحقق عند الطلب
يمكن إعادة التحقق من البيانات عند الطلب عن طريق المسار (revalidatePath
) أو عن طريق علامة التخزين المؤقت (revalidateTag
) داخل Route Handler أو Server Action.
لدى Next.js نظام وضع العلامات على الذاكرة المؤقتة لإبطال طلبات fetch
عبر المسارات.
- عند استخدام
fetch
، لديك خيار وضع علامات على إدخالات الذاكرة المؤقتة بواحدة أو أكثر من العلامات. - ثم يمكنك استدعاء
revalidateTag
لإعادة التحقق من جميع الإدخالات المرتبطة بهذه العلامة.
على سبيل المثال، يضيف طلب fetch
التالي علامة التخزين المؤقت collection
:
export default async function Page() {
const res = await fetch('https://...', { next: { tags: ['collection'] } })
const data = await res.json()
// ...
}
export default async function Page() {
const res = await fetch('https://...', { next: { tags: ['collection'] } })
const data = await res.json()
// ...
}
إذا كنت تستخدم Route Handler، يجب إنشاء رمز سري يعرفه فقط تطبيق Next.js الخاص بك. سيتم استخدام هذا الرمز لمنع محاولات إعادة التحقق غير المصرح بها. على سبيل المثال، يمكنك الوصول إلى المسار (إما يدويًا أو عبر webhook) باستخدام هيكل URL التالي:
https://<your-site.com>/api/revalidate?tag=collection&secret=<token>
import { NextRequest } from 'next/server'
import { revalidateTag } from 'next/cache'
// مثال: webhook إلى `your-website.com/api/revalidate?tag=collection&secret=<token>`
export async function POST(request: NextRequest) {
const secret = request.nextUrl.searchParams.get('secret')
const tag = request.nextUrl.searchParams.get('tag')
if (secret !== process.env.MY_SECRET_TOKEN) {
return Response.json({ message: 'رمز سري غير صالح' }, { status: 401 })
}
if (!tag) {
return Response.json({ message: 'معلمة العلامة مفقودة' }, { status: 400 })
}
revalidateTag(tag)
return Response.json({ revalidated: true, now: Date.now() })
}
import { revalidateTag } from 'next/cache'
// مثال: webhook إلى `your-website.com/api/revalidate?tag=collection&secret=<token>`
export async function POST(request) {
const secret = request.nextUrl.searchParams.get('secret')
const tag = request.nextUrl.searchParams.get('tag')
if (secret !== process.env.MY_SECRET_TOKEN) {
return Response.json({ message: 'رمز سري غير صالح' }, { status: 401 })
}
if (!tag) {
return Response.json({ message: 'معلمة العلامة مفقودة' }, { status: 400 })
}
revalidateTag(tag)
return Response.json({ revalidated: true, now: Date.now() })
}
بدلاً من ذلك، يمكنك استخدام revalidatePath
لإعادة التحقق من جميع البيانات المرتبطة بمسار.
import { NextRequest } from 'next/server'
import { revalidatePath } from 'next/cache'
export async function POST(request: NextRequest) {
const path = request.nextUrl.searchParams.get('path')
if (!path) {
return Response.json({ message: 'معلمة المسار مفقودة' }, { status: 400 })
}
revalidatePath(path)
return Response.json({ revalidated: true, now: Date.now() })
}
import { revalidatePath } from 'next/cache'
export async function POST(request) {
const path = request.nextUrl.searchParams.get('path')
if (!path) {
return Response.json({ message: 'معلمة المسار مفقودة' }, { status: 400 })
}
revalidatePath(path)
return Response.json({ revalidated: true, now: Date.now() })
}
تعلم المزيد عن إعادة التحقق عند الطلب.
معالجة الأخطاء وإعادة التحقق
إذا حدث خطأ أثناء محاولة إعادة التحقق من البيانات، سيتم الاستمرار في تقديم آخر بيانات تم إنشاؤها بنجاح من الذاكرة المؤقتة. في الطلب التالي، سيقوم Next.js بإعادة محاولة إعادة التحقق من البيانات.
عدم استخدام التخزين المؤقت للبيانات
لا يتم تخزين طلبات fetch
مؤقتًا إذا:
- تمت إضافة
cache: 'no-store'
إلى طلباتfetch
. - تمت إضافة خيار
revalidate: 0
إلى طلباتfetch
الفردية. - كان طلب
fetch
داخل Route Handler يستخدم طريقةPOST
. - جاء طلب
fetch
بعد استخدامheaders
أوcookies
. - تم استخدام خيار مقطع المسار
const dynamic = 'force-dynamic'
. - تم تكوين خيار مقطع المسار
fetchCache
لتخطي التخزين المؤقت افتراضيًا. - استخدم طلب
fetch
رؤوسAuthorization
أوCookie
وكان هناك طلب غير مخزن مؤقتًا فوقه في شجرة المكونات.
طلبات fetch
الفردية
لعدم استخدام التخزين المؤقت لطلبات fetch
الفردية، يمكنك تعيين خيار cache
في fetch
إلى 'no-store'
. سيؤدي هذا إلى جلب البيانات ديناميكيًا في كل طلب.
fetch('https://...', { cache: 'no-store' })
عرض جميع خيارات cache
المتاحة في مرجع واجهة برمجة تطبيقات fetch
.
طلبات fetch
المتعددة
إذا كان لديك عدة طلبات fetch
في مقطع مسار (مثل Layout أو Page)، يمكنك تكوين سلوك التخزين المؤقت لجميع طلبات البيانات في المقطع باستخدام خيارات تكوين المقطع.
على سبيل المثال، استخدام const dynamic = 'force-dynamic'
سيؤدي إلى جلب جميع البيانات في وقت الطلب، وعرض المقطع ديناميكيًا.
// أضف
export const dynamic = 'force-dynamic'
هناك قائمة واسعة من خيارات تكوين المقطع، مما يمنحك تحكمًا دقيقًا في السلوك الثابت والديناميكي لمقطع مسار. راجع مرجع API للمزيد.
جلب البيانات على الخادم باستخدام مكتبات الطرف الثالث
في الحالات التي تستخدم فيها مكتبة طرف ثالث لا تدعم أو تعرض fetch
(مثل قاعدة بيانات، نظام إدارة محتوى، أو عميل ORM)، يمكنك تكوين سلوك التخزين المؤقت وإعادة التحقق من تلك الطلبات باستخدام خيار تكوين مقطع المسار ودالة cache
في React.
سيعتمد ما إذا كانت البيانات مخزنة مؤقتًا أم لا على ما إذا كان مقطع المسار معروضًا بشكل ثابت أو ديناميكي. إذا كان المقطع ثابتًا (افتراضيًا)، سيتم تخزين ناتج الطلب وإعادة التحقق منه كجزء من مقطع المسار. إذا كان المقطع ديناميكيًا، لن يتم تخزين ناتج الطلب وسيتم إعادة جلبه في كل طلب عند عرض المقطع.
معلومة مفيدة:
يعمل Next.js على واجهة برمجة تطبيقات،
unstable_cache
، لتكوين سلوك التخزين المؤقت وإعادة التحقق من طلبات الطرف الثالث الفردية.
مثال
في المثال التالي:
- تم تعيين خيار
revalidate
إلى3600
، مما يعني أنه سيتم تخزين البيانات مؤقتًا وإعادة التحقق منها على الأكثر كل ساعة. - يتم استخدام دالة
cache
في React لتذكر طلبات البيانات.
import { cache } from 'react'
export const revalidate = 3600 // إعادة التحقق من البيانات على الأكثر كل ساعة
export const getItem = cache(async (id: string) => {
const item = await db.item.findUnique({ id })
return item
})
import { cache } from 'react'
export const revalidate = 3600 // إعادة التحقق من البيانات على الأكثر كل ساعة
export const getItem = cache(async (id) => {
const item = await db.item.findUnique({ id })
return item
})
على الرغم من استدعاء دالة getItem
مرتين، سيتم إجراء استعلام واحد فقط إلى قاعدة البيانات.
import { getItem } from '@/utils/get-item'
export default async function Layout({
params: { id },
}: {
params: { id: string }
}) {
const item = await getItem(id)
// ...
}
import { getItem } from '@/utils/get-item'
export default async function Layout({ params: { id } }) {
const item = await getItem(id)
// ...
}
import { getItem } from '@/utils/get-item'
export default async function Page({
params: { id },
}: {
params: { id: string }
}) {
const item = await getItem(id)
// ...
}
import { getItem } from '@/utils/get-item'
export default async function Page({ params: { id } }) {
const item = await getItem(id)
// ...
}
جلب البيانات على العميل باستخدام Route Handlers
إذا كنت بحاجة إلى جلب البيانات في مكون عميل، يمكنك استدعاء Route Handler من العميل. يتم تنفيذ Route Handlers على الخادم وإرجاع البيانات إلى العميل. هذا مفيد عندما لا تريد الكشف عن معلومات حساسة للعميل، مثل رموز API.
راجع وثائق Route Handler للحصول على أمثلة.
مكونات الخادم و Route Handlers
نظرًا لأن مكونات الخادم تعرض على الخادم، لا تحتاج إلى استدعاء Route Handler من مكون خادم لجلب البيانات. بدلاً من ذلك، يمكنك جلب البيانات مباشرة داخل مكون الخادم.
جلب البيانات على العميل باستخدام مكتبات الطرف الثالث
يمكنك أيضًا جلب البيانات على العميل باستخدام مكتبات طرف ثالث مثل SWR أو React Query. توفر هذه المكتبات واجهات برمجة تطبيقات خاصة بها لتذكر الطلبات، التخزين المؤقت، إعادة التحقق، وتحوير البيانات.
واجهات برمجة التطبيقات المستقبلية:
use
هي دالة React تقبل وتتعامل مع وعد تم إرجاعه بواسطة دالة. لفfetch
فيuse
غير موصى به حاليًا في مكونات العميل وقد يؤدي إلى إعادة عرض متعددة. تعلم المزيد عنuse
في RFC React.