🟣 Data, Server और APIs · Lesson 19
Data Fetching और Caching
Fetching बस async/await है
App Router में ज़्यादातर data के लिए useEffect या loading state की ज़रूरत नहीं। Server Component को async बनाइए और data await कीजिए — HTML पहले से भरा हुआ आता है, जो SEO के लिए perfect है।
JSX – async Server Component
// app/page.jsx — a Server Component can be async
async function getStats() {
return { students: 1200, courses: 6, rating: 4.8 } // could be a DB call
}
export default async function Home() {
const stats = await getStats()
return <p>{stats.students}+ students · {stats.courses} courses · ⭐ {stats.rating}</p>
}पुराना React तरीका (client)
- पहले खाली HTML
- useEffect → browser में fetch
- Loading spinner
- Google को content न दिखे
Next.js Server Component
- Server पर data fetch
- HTML पूरा आता है
- Spinner की ज़रूरत नहीं
- SEO के लिए perfect
API से data लाना
JSX – app/jobs/page.jsx
// app/jobs/page.jsx
async function getJobs() {
const res = await fetch('https://api.example.com/jobs?city=delhi')
if (!res.ok) throw new Error('Failed to load jobs') // → error.jsx
return res.json()
}
export default async function Jobs() {
const jobs = await getJobs()
return (
<ul>
{jobs.map((j) => <li key={j.id}>{j.title} – {j.company}</li>)}
</ul>
)
}Local files पढ़ना (Markdown blog)
Server Components Node.js modules use कर सकते हैं। EduSite का blog content/posts/ से .md files पढ़ता है:
Markdown – content/posts/how-to-start-coding.md
--- title: How to Start Coding in 2026 date: 2026-03-10 excerpt: A simple 30-day plan for complete beginners. --- ## Day 1–7: Pick one language Start with **Python** or **C** …
JS – lib/posts.js
// lib/posts.js (from the EduSite project)
import fs from 'node:fs'
import path from 'node:path'
import matter from 'gray-matter' // reads the --- front matter ---
import { marked } from 'marked' // converts Markdown → HTML
const POSTS_DIR = path.join(process.cwd(), 'content', 'posts')
export function getAllPosts() {
return fs.readdirSync(POSTS_DIR)
.filter((f) => f.endsWith('.md'))
.map((file) => {
const slug = file.replace(/\.md$/, '')
const { data } = matter(fs.readFileSync(path.join(POSTS_DIR, file), 'utf8'))
return { slug, title: data.title, date: data.date, excerpt: data.excerpt }
})
.sort((a, b) => (a.date < b.date ? 1 : -1)) // newest first
}
export function getPost(slug) {
const file = path.join(POSTS_DIR, slug + '.md')
if (!/^[a-z0-9-]+$/.test(slug) || !fs.existsSync(file)) return null
const { data, content } = matter(fs.readFileSync(file, 'utf8'))
return { slug, ...data, html: marked.parse(content) }
}
Fetch results cache करना
JS – caching के चार options
// 1) No caching (default) – fresh on every request
await fetch('https://api.example.com/price')
// 2) Cache forever (until next deploy or revalidate)
await fetch('https://api.example.com/states', { cache: 'force-cache' })
// 3) Cache, but refresh at most every 1 hour (ISR-style)
await fetch('https://api.example.com/courses', { next: { revalidate: 3600 } })
// 4) Cache with a tag so you can refresh it on demand
await fetch('https://api.example.com/courses', { next: { tags: ['courses'] } })| Data type | Best option |
|---|---|
| Live price, user dashboard | no cache (default) |
| States की list, कम बदलती | force-cache |
| Blog posts, course list | revalidate: 3600 |
| Admin courses edit करता है | tags + revalidateTag |
Revalidate: schedule पर fresh data
JS – route segment config
// app/blog/page.jsx — whole page regenerates at most every 10 minutes export const revalidate = 600
Tags से on-demand revalidation
JS – app/admin/actions.js
// app/admin/actions.js
'use server'
import { revalidateTag, revalidatePath } from 'next/cache'
export async function addCourse(formData) {
await saveCourseToDatabase(formData)
revalidateTag('courses', 'max') // every fetch tagged 'courses' is stale now
revalidatePath('/courses') // or: refresh one path
}Parallel vs sequential requests
JS – Promise.all
// ❌ Sequential: 1s + 1s + 1s = 3 seconds const course = await getCourse(slug) const reviews = await getReviews(slug) const teacher = await getTeacher(slug) // ✅ Parallel: all start together ≈ 1 second const [course, reviews, teacher] = await Promise.all([ getCourse(slug), getReviews(slug), getTeacher(slug), ])
Sequential
- getCourse ▓▓▓
- getReviews ▓▓▓
- getTeacher ▓▓▓
- ≈ 3 s
Parallel (Promise.all)
- getCourse ▓▓▓
- getReviews ▓▓▓
- getTeacher ▓▓▓
- ≈ 1 s
Client Components में fetching
Browser fetching सिर्फ़ उस data के लिए use करें जो user के देखते-देखते बदलता है (live seats, chat) या user actions पर निर्भर है।
JSX – components/LiveSeats.jsx
// components/LiveSeats.jsx — refresh seat count every 10s in the browser
'use client'
import { useEffect, useState } from 'react'
export default function LiveSeats({ slug }) {
const [seats, setSeats] = useState(null)
useEffect(() => {
const load = () => fetch(`/api/seats?course=${slug}`).then((r) => r.json()).then((d) => setSeats(d.left))
load()
const id = setInterval(load, 10000)
return () => clearInterval(id)
}, [slug])
return <p>{seats === null ? 'Checking seats…' : `${seats} seats left`}</p>
}आम गलतियाँ
- Server Component से अपना ही
/api/...route call करना → बेकार HTTP hop; function (जैसेgetCourses()) सीधे call करें। - fetch के अपने आप cache होने की उम्मीद (पुराना Next.js 13/14 behaviour) →
force-cacheयाrevalidateजोड़ें। - Independent requests को एक-एक करके await करना →
Promise.alluse करें। res.okcheck न करना → 500 error page JSON की तरह parse होकर crash।
सारांश
- Server Components: data सीधे
async+await(API, files, database)। - Caching opt-in है:
force-cache,revalidate,tags। - Updates के बाद
revalidateTag/revalidatePath; speed के लिएPromise.all।
✅ Practice
3 Markdown files के साथ content/posts बनाइए और उन्हें date के हिसाब से /blog पर दिखाइए। फिर next: { revalidate: 60 } के साथ कोई public API fetch करके fetch होने का time दिखाइए।
अक्सर पूछे जाने वाले प्रश्न (FAQ)
क्या Next.js 16 में fetch default रूप से cache होता है?
नहीं। Next.js 15 से fetch requests default रूप से cache नहीं होतीं। Response cache करने के लिए cache: 'force-cache' या next: { revalidate: seconds } जोड़ें।
क्या Next.js में data load करने के लिए useEffect चाहिए?
ज़्यादातर pages के लिए नहीं। Server Component को async बनाइए और data await कीजिए। useEffect सिर्फ़ उस data के लिए है जो user interaction के बाद browser में load होना चाहिए।
revalidateTag क्या है?
Data बदलने के बाद (जैसे Server Action में) call होने वाला function। यह उस tag वाले सारे fetches को stale mark करता है, ताकि अगले visitor को fresh data मिले। Next.js 16 में profile दें: revalidateTag('courses', 'max')।
