Server vs Client Components
Default रूप से सब Server Component
App Router में हर component Server Component होता है जब तक आप अलग न कहें। यह server पर चलता है, files और database सीधे पढ़ सकता है, और browser को सिर्फ़ HTML भेजता है — उस component के लिए zero JavaScript।
// app/courses/page.jsx — Server Component (no directive needed)
import { courses } from '@/lib/courses'
import fs from 'node:fs' // ✅ Node APIs allowed on the server
export default async function Courses() {
const note = fs.readFileSync('notice.txt', 'utf8') // runs on server only
return (
<main>
<p>{note}</p>
{courses.map((c) => <h2 key={c.slug}>{c.title}</h2>)}
</main>
)
}Client Components: 'use client'
जब interactivity चाहिए — clicks, typing, state, browser APIs — file के top पर 'use client' लिखें।
// components/LikeButton.jsx — Client Component
'use client' // must be the very first line
import { useState } from 'react'
export default function LikeButton() {
const [likes, setLikes] = useState(0)
return <button onClick={() => setLikes(likes + 1)}>👍 {likes}</button>
}कब कौन सा
| आपको चाहिए… | Server | Client |
|---|---|---|
| Data fetch / database query | ✅ | ⚠️ API से |
| API keys secret रखना | ✅ | ❌ |
| onClick, onChange, live validation वाले forms | ❌ | ✅ |
| useState, useEffect, useContext | ❌ | ✅ |
| window, localStorage, geolocation | ❌ | ✅ |
| छोटा JavaScript bundle | ✅ | JS जोड़ता है |
क्या कहाँ चलता है
Client boundary
'use client' एक boundary बनाता है। वह file और उसके सारे imports client code बन जाते हैं। इसलिए directive को tree में जितना हो सके नीचे रखें।
Pattern: server page + छोटा client island
// app/courses/page.jsx (Server Component)
import { searchCourses } from '@/lib/courses'
import CourseCard from '@/components/CourseCard' // server
import CourseSearch from './CourseSearch' // client island
export default async function CoursesPage({ searchParams }) {
const { q = '' } = await searchParams
const list = searchCourses(q) // data on server
return (
<div className="container">
<h1>All Courses</h1>
<CourseSearch initial={q} /> {/* only this ships JS */}
<div className="grid">
{list.map((c) => <CourseCard key={c.slug} course={c} />)}
</div>
</div>
)
}
Server Components को children में भेजना
Client Component, Server Component को import नहीं कर सकता, पर उसे prop या children के रूप में receive कर सकता है।
// components/Tabs.jsx (client)
'use client'
import { useState } from 'react'
export default function Tabs({ first, second }) {
const [tab, setTab] = useState(0)
return (
<div>
<button onClick={() => setTab(0)}>Syllabus</button>
<button onClick={() => setTab(1)}>Reviews</button>
{tab === 0 ? first : second}
</div>
)
}
// app/courses/[slug]/page.jsx (server)
<Tabs
first={<Syllabus slug={slug} />} // Server Components passed as props
second={<Reviews slug={slug} />} // they still render on the server
/>Secrets को server पर रखना
// lib/db.js
import 'server-only' // npm i server-only → build error if imported in client code
import mysql from 'mysql2/promise'
export const db = mysql.createPool({ password: process.env.DB_PASSWORD /* … */ })NEXT_PUBLIC_ prefix के बिना वाले environment variables कभी browser को नहीं भेजे जाते।
आम गलतियाँ
- सिर्फ़ एक button के लिए page.jsx पर
'use client'→ पूरा page JS भेजता है। Button अलग निकालें। - Server से Client को functions props में भेजना (
onSave={save}) → serializable नहीं; Server Action use करें। - Server Component में
window→ "window is not defined"। - Imports के बाद
'use client'→ यह पहली line होनी चाहिए।
सारांश
- Server Components (default): data, secrets, zero JS।
- Client Components (
'use client'): state, events, browser APIs। - Client islands छोटे रखें और server content को children में भेजें।
Server-rendered course page बनाइए और उसमें client LikeButton और एक client Tabs component जोड़िए जो दो server-rendered sections props में ले।
