دریافت داده, کش کردن و اعتبارسنجی مجدد
در هر برنامهای، دریافت داده (data fetching) هستهی اصلی به شمار میرود. این صفحه نحوهی دریافت، کش کردن (cache) و اعتبارسنجی مجدد (revalidate) داده در React و Next.js را شرح میدهد.
چهار روش برای دریافت داده وجود دارد:
- در سرور، با
fetch - در سرور، با کتابخانههای شخص ثالث
- در کلاینت، از طریق یک Route Handler
- در کلاینت، با کتابخانههای شخص ثالث.
دریافت داده در سرور با fetch
Next.js قابلیت fetch Web API (opens in a new tab) را گسترش میدهد تا پیکربندی رفتار کش کردن و اعتبارسنجی مجدد را برای هر درخواست دریافت داده در سرور امکانپذیر سازد. React نیز fetch را گسترش میدهد تا به صورت خودکار درخواستهای دریافت داده را در هنگام رندر کردن درخت کامپوننتهای React به خاطر بسپارد memoize.
شما میتوانید از fetch با async/await در کامپوننت های سرور، هندلرهای مسیر و اکشن های سرور استفاده کنید.
برای مثال :
async function getData() {
const res = await fetch('https://api.example.com/...')
// The return value is *not* serialized
// You can return Date, Map, Set, etc.
if (!res.ok) {
// This will activate the closest `error.js` Error Boundary
throw new Error('Failed to fetch data')
}
return res.json()
}
export default async function Page() {
const data = await getData()
return <main></main>
}Good to know:
- Next.js هنگام دریافت داده در کامپوننت های سرور، توابع مفیدی مانند
کوکی هاوهدرهارا در اختیار شما قرار میدهد. این موارد باعث میشوند مسیر به صورت داینامیک رندر شود زیرا آنها به اطلاعات زمان درخواست وابسته هستند.- در هندلرهای مسیر، درخواستهای
fetchبه خاطر سپرده نمیشوند not memoized زیرا هندلرهای مسیر بخشی از درخت کامپوننتهای React نیستند.- در اکشن های سرور، درخواستهای
fetchکش نمیشوند (تنظیمات پیشفرضcache: no-store).- To use
async/awaitin a Server Component with TypeScript, you'll need to use TypeScript5.1.3or higher and@types/react18.2.8or higher.- برای استفاده از
async/awaitدر یک کامپوننت سرور با تایپ اسکریپت، به تایپ اسکریپت ۵.۱.۳ یا بالاتر و@types/react18.2.8یا بالاتر نیاز دارید.
کش کردن داده
ذخیرهسازی (Caching) دادهها را ذخیره میکند تا نیازی به دریافت مجدد آنها از منبع داده در هر درخواست نباشد.
به طور پیشفرض، Next.js به طور خودکار مقادیر برگشتی fetch را در کش داده روی سرور ذخیره میکند. این بدان معناست که دادهها میتوانند در زمان ساخت یا زمان درخواست دریافت شوند، ذخیره شوند و در هر درخواست داده مجدداً مورد استفاده قرار گیرند.
// 'force-cache' is the default, and can be omitted
fetch('https://...', { cache: 'force-cache' })با این حال، استثناهایی وجود دارد، درخواستهای fetch در موارد زیر ذخیره نمیشوند:
- زمانی که داخل یک اکشن سرور Server Action استفاده شوند.
- زمانی که داخل یک هندلر مسیر که از متد
POSTاستفاده میکند، استفاده شوند.
کش داده چیست؟
Data Cache یک حافظه کش HTTP پایدار است. بسته به پلتفرم شما، این حافظه کش میتواند به صورت خودکار مقیاسگذاری شود و در چندین منطقه به اشتراک گذاشته شود (opens in a new tab).
دربارهٔ Data Cache بیشتر بیاموزید.
اعتبارسنجی مجدد داده
اعتبارسنجی مجدد فرآیندی است که کش داده را پاکسازی میکند و آخرین دادهها را دوباره دریافت میکند. این کار زمانی مفید است که دادههای شما تغییر میکنند و میخواهید مطمئن شوید که آخرین اطلاعات را نشان میدهید.
دادههای کش شده را میتوان به دو روش اعتبارسنجی مجدد کرد:
- اعتبارسنجی مجدد مبتنی بر زمان: دادهها را به طور خودکار پس از گذشت زمان مشخصی دوباره دریافت کنید. این برای دادههایی که به ندرت تغییر میکنند و تازگی آنها چندان مهم نیست، مفید است.
- اعتبارسنجی مجدد بر اساس تقاضا: دادهها را به صورت دستی بر اساس یک رویداد (مثلاً ارسال فرم) دوباره دریافت کنید.اعتبارسنجی مجدد بر اساس تقاضا میتواند از یک رویکرد مبتنی بر برچسب یا مبتنی بر مسیر برایاعتبارسنجی مجدد گروههایی از دادهها به طور همزمان استفاده کند. این زمانی مفید است که میخواهید اطمینان حاصل کنید که آخرین دادهها در اسرع وقت نشان داده میشوند (مثلاً زمانی که محتوای سیستم مدیریت محتوای بدون سرور شما بهروز میشود).
اعتبارسنجی مجدد مبتنی بر زمان
برایاعتبارسنجی مجدد دادهها در یک فاصله زمانی، میتوانید از گزینه next.revalidate در fetch برای تنظیم طول عمر کش یک منبع (بر حسب ثانیه) استفاده کنید.
fetch('https://...', { next: { revalidate: 3600 } })به طور جایگزین، برایاعتبارسنجی مجدد تمام درخواستهای fetch در یک بخش مسیر، میتوانید از گزینههای پیکربندی بخش Segment Config Options استفاده کنید.
export const revalidate = 3600 // revalidate at most every hourاگر چندین درخواست fetch در یک مسیر رندر شده به صورت ایستا دارید و هر کدام فرکانساعتبارسنجی مجدد متفاوتی دارند، کمترین زمان برای همه درخواستها استفاده خواهد شد. برای مسیرهای رندر شده به صورت داینامیک، هر درخواست fetch به طور مستقل اعتبارسنجی مجدد خواهد شد.
درباره ی اعتبارسنجی مجدد مبتنی بر زمان بیشتر بیاموزید.
اعتبارسنجی مجدد بر اساس تقاضا
دادهها را میتوان بر اساس مسیر (revalidatePath) یا برچسب حافظه کش (revalidateTag) درون یک 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()
// ...
}سپس میتوانید این فراخوانی fetch با تگ collection را با فراخوانی revalidateTag در یک Server Action اعتبارسنجی مجدد کنید:
'use server'
import { revalidateTag } from 'next/cache'
export default async function action() {
revalidateTag('collection')
}دربارهٔ اعتبارسنجی مجدد بر اساس تقاضا بیشتر بیاموزید.
هندل کردن خطا و اعتبارسنجی مجدد
اگر در حین تلاش برای اعتبارسنجی مجدد داده خطایی رخ دهد، آخرین دادههای تولید شده با موفقیت همچنان از حافظه کش ارائه خواهند شد. در درخواست بعدی بعدی، Next.js مجدداً تلاش میکند دادهها را اعتبارسنجی مجدد کند.
انصراف از ذخیرهسازی داده (Data Caching)
درخواستهای fetch در صورتهای زیر کش نمیشوند:
- گزینه
cache: 'no-store'به درخواستهایfetchاضافه شود. - گزینه
revalidate: 0به تک تک درخواستهایfetchاضافه شود. - درخواست
fetchداخل یک هندلر مسیر باشد که از متدPOSTاستفاده میکند. - درخواست
fetchبعد از استفاده ازheadersیاcookiesبیاید. - گزینه بخش مسیر
const dynamic = 'force-dynamic'استفاده شود. - گزینه بخش مسیر
fetchCacheبه صورت پیشفرض برای رد شدن از کش پیکربندی شود. - درخواست
fetchاز هدرهایAuthorizationیاCookieاستفاده کند و یک درخواست بدون حافظه کش در بالای آن در درخت کامپوننت وجود داشته باشد.
تک تک درخواستهای fetch
برای انصراف از کش برای تک تک درخواستهای fetch، میتوانید گزینه cache را در fetch روی 'no-store' تنظیم کنید. این کار باعث میشود دادهها به صورت داینامیک و در هر درخواست دریافت شوند.
fetch('https://...', { cache: 'no-store' })تمام گزینههای cache موجود را در مرجع API fetch مشاهده کنید.
چندین درخواست fetch
اگر چندین درخواست fetch در یک بخش مسیر (مانند طرح بندی یا صفحه) دارید، میتوانید رفتار کش تمام درخواستهای داده در بخش را با استفاده از گزینههای پیکربندی بخش Segment Config Options پیکربندی کنید.
با این حال، توصیه میکنیم رفتار کش هر درخواست fetch را به صورت جداگانه پیکربندی کنید. این کار کنترل دقیقتری بر رفتار کش به شما میدهد.
دریافت داده ها بر روی سرور با کتابخانه های شخص ثالث
در موارد استفاده از یک کتابخانه شخص ثالث که از fetch پشتیبانی نمیکند یا آن را در معرض نمایش قرار نمیدهد (به عنوان مثال، یک پایگاه داده، CMS یا یک کلاینت ORM)، میتوانید رفتار کش و اعتبارسنجی مجدد آن درخواستها را با استفاده از گزینه پیکربندی بخش مسیر Route Segment Config Option و تابع cache متعلق به React پیکربندی کنید.
اینکه آیا دادهها کش شوند یا نه به این بستگی دارد که بخش مسیر به صورت ایستا یا داینامیک رندر شود. اگر بخش ایستا (پیشفرض) باشد، خروجی درخواست کش و بر اساس بخش مسیر اعتبارسنجی مجدد خواهد شد. اگر بخش داینامیک باشد، خروجی درخواست کش نمیشود و در هر درخواستی که بخش رندر میشود، دوباره دریافت خواهد شد.
همچنین میتوانید از API آزمایشی unstable_cache استفاده کنید.
مثال
در مثال زیر:
- از تابع
cacheمتعلق به React برای memoize کردن درخواستهای داده استفاده میشود. - گزینه
revalidateدر بخشهای Layout و Page روی3600تنظیم شده است، به این معنی که دادهها حداکثر هر ساعت کش و اعتبارسنجی مجدد خواهند شد.
import { cache } from 'react'
export const getItem = cache(async (id: string) => {
const item = await db.item.findUnique({ id })
return item
})اگرچه تابع getItem دو بار فراخوانی میشود، اما تنها یکبار کوئری به پایگاه داده ارسال خواهد شد.
import { getItem } from '@/utils/get-item'
export const revalidate = 3600 // revalidate the data at most every hour
export default async function Layout({
params: { id },
}: {
params: { id: string }
}) {
const item = await getItem(id)
// ...
}import { getItem } from '@/utils/get-item'
export const revalidate = 3600 // revalidate the data at most every hour
export default async function Page({
params: { id },
}: {
params: { id: string }
}) {
const item = await getItem(id)
// ...
}دریافت داده در کلاینت با هندلرهای مسیر
اگر نیاز به دریافت داده در یک کامپوننت کلاینت دارید، میتوانید یک هندلر مسیر را از کلاینت فراخوانی کنید. هندلرهای مسیر روی سرور اجرا میشوند و دادهها را به کلاینت برمیگردانند. این زمانی مفید است که نمیخواهید اطلاعات حساس مانند توکنهای API را در معرض دید کلاینت قرار دهید.
برای دیدن مثالها به مستندات هندلر مسیر مراجعه کنید.
کامپوننت های سرور و هندلرهای مسیر
از آنجایی که کامپوننت های سرور روی سرور رندر میشوند، نیازی به فراخوانی یک هندلر مسیر از یک کامپوننت سرور برای دریافت داده ندارید. در عوض، میتوانید دادهها را مستقیماً داخل کامپوننت سرور دریافت کنید.
دریافت داده در کلاینت با کتابخانههای شخص ثالث
همچنین میتوانید با استفاده از یک کتابخانه شخص ثالث مانند SWR (opens in a new tab) یا TanStack Query (opens in a new tab) دادهها را در کلاینت دریافت کنید. این کتابخانهها APIهای خاص خود را برای memoize کردن درخواستها، کش کردن، اعتبارسنجی مجدد و تغییر دادن دادهها ارائه میدهند.
APIهای آینده:
useیک تابع React است که یک promise برگشتی از یک تابع را میپذیرد و آن را مدیریت میکند. در حال حاضر، wrappingfetchدرuseدر کامپوننت های کلاینت توصیه نمیشود و ممکن است باعث چندین رندر مجدد شود. برای اطلاعات بیشتر دربارهuseبه مستندات React (opens in a new tab) مراجعه کنید.