Client Component — "use client", qachon kerak, Server Component dan farqi
Muammodan boshlaylik
Oldingi darsda Server Component ni o'rgandik — serverda ishlaydi, DB ga to'g'ridan-to'g'ri ulanadi, brauzerga JS yuborilmaydi. Zo'r.
Lekin hamma narsa Server Component bo'la olmaydi. Tasavvur qiling — saytda "Qorong'i rejim" tugmasi bor. Foydalanuvchi bosadi — fon qorayadi. Bu holat brauzerda saqlanadi va o'zgaradi. Server bu haqda hech narsa bilmaydi.
Yoki qidiruv qutisi — foydalanuvchi yozayotganda natijalar o'zgarib turadi. Bu ham brauzerda ishlaydi.
Bunday interaktiv qismlar uchun Client Component kerak.
'use client' nima
'use client' — faylning birinchi qatoriga yoziladigan direktiva. Bu Next.js ga shuni aytadi: "bu komponent va uning barcha import lari brauzerda ishlaydi."
'use client' // ← shu qator yetarli
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return (
<button onClick={() => setCount(c => c + 1)}>
Bosimlar: {count}
</button>
)
}
'use client' yozilgan fayl va u import qilgan barcha fayllar — Client Component bo'ladi.
Client Component qachon kerak
Quyidagi holatlardan biri bo'lsa — Client Component kerak:
1. Holat (state) boshqarish
'use client'
const [isOpen, setIsOpen] = useState(false)
2. Foydalanuvchi harakati (event)
'use client'
<button onClick={handleClick}>Bosing</button>
<input onChange={handleChange} />
3. Brauzer API lari
'use client'
localStorage.setItem('theme', 'dark')
window.scrollTo(0, 0)
document.title = 'Yangi sarlavha'
4. Brauzerda ishlaydigan kutubxonalar
'use client'
import { motion } from 'framer-motion' // animatsiya
import { Chart } from 'recharts' // grafik
Amaliy misol — Dropdown menu
Server Component da dropdown yasab bo'lmaydi — ochiq/yopiq holati useState kerak:
// components/Dropdown.tsx
'use client'
import { useState } from 'react'
export function Dropdown({ items }: { items: string[] }) {
const [isOpen, setIsOpen] = useState(false)
return (
<div>
<button onClick={() => setIsOpen(o => !o)}>
Menyu {isOpen ? '▲' : '▼'}
</button>
{isOpen && (
<ul>
{items.map(item => (
<li key={item}>{item}</li>
))}
</ul>
)}
</div>
)
}
Bu komponent Server Component dan chaqiriladi — items props orqali uzatiladi:
// app/page.tsx — Server Component
import { Dropdown } from '@/components/Dropdown'
export default async function Page() {
const categories = await db.getCategories() // serverda
return (
<div>
<h1>Bosh sahifa</h1>
<Dropdown items={categories} /> {/* Client Component */}
</div>
)
}
Ma'lumot serverda olinadi, interaktivlik brauzerda ishlaydi. Ikkalasi o'z joyida.
'use client' chegarasi
'use client' yozilgan fayl — chegara (boundary). Shu fayldan pastdagi hamma narsa Client Component bo'ladi.
app/page.tsx → Server Component
└── Sidebar.tsx → Server Component
└── Header.tsx → 'use client' ← chegara
└── SearchBar.tsx → Client Component (import qilingan)
└── ThemeToggle.tsx → Client Component (import qilingan)
Header.tsx da 'use client' bor — u import qilgan SearchBar va ThemeToggle ham avtomatik Client Component bo'ladi, ularda 'use client' yozmasangiz ham.
Muhim qoida — 'use client' ni pastga suring
Ko'pchilik yangi boshlovchilar butun sahifani Client Component qilib qo'yadi:
// ❌ — butun sahifa Client Component
'use client'
export default function Page() {
const [count, setCount] = useState(0)
return (
<div>
<h1>Sarlavha</h1> {/* statik — serverda bo'lishi kerak edi */}
<p>Tavsif matni</p> {/* statik — serverda bo'lishi kerak edi */}
<button onClick={...}>{count}</button> {/* bu uchun 'use client' kerak */}
</div>
)
}
To'g'ri yondashuv — faqat interaktiv qismni Client Component qilish:
// ✅ — faqat tugma Client Component
// app/page.tsx — Server Component
import { Counter } from './Counter'
export default function Page() {
return (
<div>
<h1>Sarlavha</h1> {/* serverda render */}
<p>Tavsif matni</p> {/* serverda render */}
<Counter /> {/* faqat shu Client Component */}
</div>
)
}
// Counter.tsx — Client Component
'use client'
export function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(c => c + 1)}>{count}</button>
}
Natija — <h1> va <p> brauzerga JS sifatida yuklanmaydi. Faqat Counter ning kodi yuklanadi.
Server Component ni Client Component ga props orqali uzatish
Client Component Server Component ni import qila olmaydi. Lekin Server Component ni children orqali uzatish mumkin:
// ✅ — children orqali
// app/page.tsx — Server Component
import { Modal } from './Modal'
import { UserProfile } from './UserProfile' // Server Component
export default async function Page() {
const user = await db.getUser()
return (
<Modal>
<UserProfile user={user} /> {/* Server Component — children sifatida */}
</Modal>
)
}
// Modal.tsx — Client Component
'use client'
export function Modal({ children }) {
const [isOpen, setIsOpen] = useState(true)
if (!isOpen) return null
return (
<div className="modal">
{children} {/* Server Component shu yerda render bo'ladi */}
<button onClick={() => setIsOpen(false)}>Yopish</button>
</div>
)
}
children — Server Component da render bo'ladi, Client Component ga tayyor HTML sifatida uzatiladi.
Tez-tez uchraydigan xatolar
1. 'use client' ni faylning birinchi qatoriga qo'ymaslik
// ❌ — comment yoki bo'sh qator oldin bo'lsa ham xato
// Bu komponent Client Component
'use client'
// ✅ — birinchi qator bo'lishi shart
'use client'
// Bu komponent Client Component
2. Server Component dan Server Component ni Client Component orqali import qilish
// ❌
'use client'
import { ServerComp } from './ServerComp' // ishlamaydi
// ✅ — children orqali uzating (yuqoridagi misol)
3. Keraksiz joyda 'use client' ishlatish
// ❌ — bu komponentda brauzer API yo'q, 'use client' kerak emas
'use client'
export function Title({ text }) {
return <h1>{text}</h1>
}
// ✅ — Server Component bo'lishi yaxshiroq
export function Title({ text }) {
return <h1>{text}</h1>
}
Xulosa
Client Component — brauzerda ishlaydigan komponent. 'use client' direktiva bilan belgilanadi.
Qachon kerak: useState, useEffect, onClick, localStorage, brauzerda ishlaydigan kutubxonalar.
Asosiy qoida: 'use client' ni imkon qadar pastga suring — faqat interaktiv qismga. Statik kontent Server Component da qolsin.
Butun sahifa 'use client' → ❌ (bundle katta, tezlik past)
Faqat interaktiv qism → ✅ (optimal)
Server Component → Client Component: props orqali ma'lumot uzatish.
Client Component → Server Component: to'g'ridan-to'g'ri import emas, children orqali.
Keyingi dars
12-dars: Server va Client Component birga ishlatish — composition pattern
Ikkalasini birgalikda to'g'ri tashkil qilish — real loyihalarda qanday arxitektura quriladi.