Server Component da fetch — caching, revalidate, no-store
Muammodan boshlaylik
Siz bir sahifada ikkita komponent yozdingiz. Ikkalasi ham bir xil API dan foydalanuvchi ma'lumotini oladi:
// Header.tsx
const user = await fetch('https://api.example.com/user/1').then(r => r.json())
// Sidebar.tsx
const user = await fetch('https://api.example.com/user/1').then(r => r.json())
Bir xil URL ga ikki marta so'rov ketadimi? Serverga yukmi oshadi?
Next.js da — yo'q. Bir xil so'rov avtomatik deduplikatsiya qilinadi. Bitta so'rov ketadi, natija ikkalasiga beriladi.
Bu — Next.js ning fetch ni qanday kengaytirganining bir misoli.
Next.js fetch ni kengaytirgan
Brauzer fetch — oddiy HTTP so'rov. Next.js Server Component dagi fetch ni kengaytirgan — kesh, revalidatsiya, deduplikatsiya qo'shilgan.
Oddiy fetch:
fetch('/api/data') → HTTP so'rov → javob
Next.js fetch:
fetch('/api/data') → keshda bormi? → bor → keshdan qaytaradi
→ yo'q → HTTP so'rov → keshga saqlaydi
3 ta kesh rejimi
1. force-cache — keshda saqlash (default)
const data = await fetch('https://api.example.com/posts', {
cache: 'force-cache' // default — yozmasangiz ham shu
}).then(r => r.json())
Birinchi so'rovda ma'lumot olinadi va keshga saqlanadi. Keyingi so'rovlarda — keshdan qaytariladi. Server ga qayta so'rov ketmaydi.
Bu — Static Rendering ga mos. Build vaqtida bir marta olinadi.
2. no-store — keshlamaslik
const data = await fetch('https://api.example.com/prices', {
cache: 'no-store'
}).then(r => r.json())
Har so'rovda yangi ma'lumot olinadi. Keshlanmaydi.
Bu — Dynamic Rendering ga mos. Har foydalanuvchi uchun yangi ma'lumot.
3. revalidate — vaqt asosida yangilash
const data = await fetch('https://api.example.com/news', {
next: { revalidate: 3600 } // 1 soatda bir yangilanadi
}).then(r => r.json())
Ma'lumot keshlanadi, lekin belgilangan vaqtdan keyin yangilanadi.
Bu — ISR ga mos.
Kesh qanday ishlaydi — vizual
Birinchi so'rov:
fetch('/api/posts') → keshda yo'q → API ga so'rov → keshga saqlaydi → qaytaradi
Ikkinchi so'rov (force-cache):
fetch('/api/posts') → keshda bor → API ga so'rov ketmaydi → keshdan qaytaradi
Ikkinchi so'rov (no-store):
fetch('/api/posts') → keshni tekshirmaydi → API ga so'rov → qaytaradi
Ikkinchi so'rov (revalidate: 3600, 1 soat o'tmagan):
fetch('/api/posts') → keshda bor, muddati o'tmagan → keshdan qaytaradi
Ikkinchi so'rov (revalidate: 3600, 1 soat o'tgan):
fetch('/api/posts') → keshda bor, muddati o'tgan → API ga so'rov → keshni yangilaydi
Deduplikatsiya — bir xil so'rov bir marta
Bir render davomida bir xil URL ga bir necha marta fetch qilinsa — Next.js faqat bitta so'rov yuboradi:
// app/page.tsx
export default async function Page() {
return (
<div>
<Header /> {/* ichida fetch('/api/user') */}
<Sidebar /> {/* ichida fetch('/api/user') */}
<MainContent /> {/* ichida fetch('/api/user') */}
</div>
)
}
Uchta komponent bir xil URL ga so'rov qiladi — lekin server ga bitta so'rov ketadi. Natija uchtalasiga beriladi.
Bu faqat GET so'rovlari va bir render davomida ishlaydi.
Teglar bilan kesh boshqarish
revalidateTag bilan ishlash uchun fetch ga teg qo'shiladi:
// Teg bilan fetch
const posts = await fetch('https://api.example.com/posts', {
next: { tags: ['posts'] }
}).then(r => r.json())
const post = await fetch(`https://api.example.com/posts/${id}`, {
next: {
tags: ['posts', `post-${id}`],
revalidate: 3600
}
}).then(r => r.json())
Yangi post qo'shilganda:
import { revalidateTag } from 'next/cache'
revalidateTag('posts') // 'posts' tegli barcha fetch lar yangilanadi
fetch ishlatilmasa — unstable_cache
Ba'zan fetch emas, to'g'ridan-to'g'ri DB so'rovi ishlatiladi. Bunday holda unstable_cache (Next.js 14) yoki cacheTag / cacheLife (Next.js 15) ishlatiladi:
// Next.js 14
import { unstable_cache } from 'next/cache'
const getCachedPosts = unstable_cache(
async () => {
return await db.select().from(posts) // DB so'rovi
},
['posts-cache'], // kesh kaliti
{
revalidate: 3600, // 1 soatda bir
tags: ['posts'], // revalidateTag uchun
}
)
export default async function Page() {
const posts = await getCachedPosts()
return <PostList posts={posts} />
}
Amaliy misol — blog sahifasi
// app/blog/page.tsx — ISR, 1 soatda bir yangilanadi
export default async function BlogPage() {
const posts = await fetch('https://api.example.com/posts', {
next: {
revalidate: 3600,
tags: ['posts']
}
}).then(r => r.json())
return (
<ul>
{posts.map(post => (
<li key={post.id}>
<a href={`/blog/${post.slug}`}>{post.title}</a>
</li>
))}
</ul>
)
}
// app/blog/[slug]/page.tsx — ISR, 1 soatda bir
export default async function BlogPost({ params }) {
const { slug } = await params
const post = await fetch(`https://api.example.com/posts/${slug}`, {
next: {
revalidate: 3600,
tags: ['posts', `post-${slug}`]
}
}).then(r => r.json())
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
)
}
// app/dashboard/page.tsx — Dynamic, har so'rovda yangi
import { cookies } from 'next/headers'
export default async function DashboardPage() {
const cookieStore = await cookies()
const token = cookieStore.get('token')?.value
const user = await fetch('https://api.example.com/me', {
cache: 'no-store',
headers: { Authorization: `Bearer ${token}` }
}).then(r => r.json())
return <h1>Salom, {user.name}</h1>
}
Tez-tez uchraydigan xatolar
1. no-store va revalidate birga ishlatish
// ❌ — qarama-qarshi, no-store ustun keladi
const data = await fetch('/api/data', {
cache: 'no-store',
next: { revalidate: 60 } // e'tiborga olinmaydi
})
// ✅ — bittasini tanlang
const data = await fetch('/api/data', { cache: 'no-store' })
// yoki
const data = await fetch('/api/data', { next: { revalidate: 60 } })
2. Client Component da server fetch keshini kutish
// ❌ — Client Component da fetch — Next.js keshi ishlamaydi
'use client'
useEffect(() => {
fetch('/api/posts') // bu oddiy brauzer fetch, Next.js keshi yo'q
}, [])
// ✅ — Server Component da fetch
export default async function Page() {
const posts = await fetch('/api/posts', { next: { revalidate: 60 } })
.then(r => r.json())
}
Next.js fetch keshi faqat Server Component da ishlaydi.
3. Har bir fetch uchun alohida revalidate o'rniga sahifa darajasida belgilash
// ❌ — har fetch da takrorlanadi
const a = await fetch('/api/a', { next: { revalidate: 3600 } })
const b = await fetch('/api/b', { next: { revalidate: 3600 } })
const c = await fetch('/api/c', { next: { revalidate: 3600 } })
// ✅ — sahifa darajasida bir marta
export const revalidate = 3600
const a = await fetch('/api/a').then(r => r.json())
const b = await fetch('/api/b').then(r => r.json())
const c = await fetch('/api/c').then(r => r.json())
Xulosa
Next.js fetch — oddiy fetch emas, kesh va revalidatsiya qo'shilgan.
cache: 'force-cache' → keshda saqlash, Static uchun (default)
cache: 'no-store' → keshlamaslik, Dynamic uchun
next: { revalidate: 60 } → 60 soniyada bir yangilash, ISR uchun
next: { tags: ['posts'] } → revalidateTag bilan yangilash uchun
Bir xil URL — bir so'rov (deduplikatsiya). DB so'rovlari uchun unstable_cache.
Keyingi dars
18-dars: Parallel va Sequential data fetching — farqi, qachon qaysinisi
Bir sahifada bir nechta ma'lumot olish kerak bo'lganda — ketma-ket yoki parallel, qaysi usul qachon mos.