d8a80f6272
이름만 다른(표기 변형) [[위키링크]]를 대상 문서의 canonical 제목으로 치환해 끊겼던 1,200개 링크를 연결. 제목/파일명 정규화 일치만 적용하고 별칭 매칭은 과병합 위험으로 제외(애매성 가드). 원본은 _link_reconcile_backup/ 에 백업. 도구: Datacollect/scripts/link_reconcile_apply.mjs Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
176 lines
5.3 KiB
Markdown
176 lines
5.3 KiB
Markdown
---
|
|
id: wiki-2026-0508-client-components
|
|
title: Client Components
|
|
category: 10_Wiki/Topics
|
|
status: verified
|
|
canonical_id: self
|
|
aliases: [RSC Client Components, "use client"]
|
|
duplicate_of: none
|
|
source_trust_level: A
|
|
confidence_score: 0.9
|
|
verification_status: applied
|
|
tags: [react, nextjs, rsc, frontend, hydration]
|
|
raw_sources: []
|
|
last_reinforced: 2026-05-10
|
|
github_commit: pending
|
|
tech_stack:
|
|
language: typescript
|
|
framework: react/nextjs
|
|
---
|
|
|
|
# Client Components
|
|
|
|
## 매 한 줄
|
|
> **"매 interactive boundary"**. Client Components 매 React Server Components (RSC) 매 architecture 의 매 interactive half — `'use client'` directive 매 매 module-level boundary marker, 매 hydration + state + browser API 매 가능한 영역. 매 2026 현재 Next.js 13+ App Router / Remix Single Fetch / TanStack Start 의 default model.
|
|
|
|
## 매 핵심
|
|
|
|
### 매 boundary model
|
|
- `'use client'` 매 file-top directive — 매 module 부터 dependent tree 매 client bundle 에 포함.
|
|
- Server Component (default) 매 server-only render — 매 zero JS shipped.
|
|
- Client Component 매 hydrate — `useState` / `useEffect` / event handler / browser API 매 가능.
|
|
|
|
### 매 핵심 properties
|
|
- **Composability**: Server → Client 매 OK (props 통해), Client → Server 매 NOT (children prop slot 만 OK).
|
|
- **Serialization**: Server → Client props 매 serializable 만 (no functions, classes, Date OK via 2026 RSC payload).
|
|
- **Bundle**: 매 leaf client component 만 ship — 매 root 에서 'use client' 매 X.
|
|
|
|
### 매 응용
|
|
1. Form 매 controlled input + validation.
|
|
2. Animation / transition (Framer Motion, View Transitions API).
|
|
3. Browser API (geolocation, clipboard, IndexedDB).
|
|
4. Real-time (WebSocket, SSE consumer).
|
|
|
|
## 💻 패턴
|
|
|
|
### Basic client component
|
|
```tsx
|
|
'use client';
|
|
|
|
import { useState } from 'react';
|
|
|
|
export function Counter() {
|
|
const [n, setN] = useState(0);
|
|
return <button onClick={() => setN(n + 1)}>Count: {n}</button>;
|
|
}
|
|
```
|
|
|
|
### Server Component → Client Component (props)
|
|
```tsx
|
|
// page.tsx (Server)
|
|
import { getProducts } from '@/lib/db';
|
|
import { ProductGrid } from './ProductGrid';
|
|
|
|
export default async function Page() {
|
|
const products = await getProducts(); // server fetch
|
|
return <ProductGrid initial={products} />;
|
|
}
|
|
```
|
|
|
|
```tsx
|
|
// ProductGrid.tsx (Client — interactive filter)
|
|
'use client';
|
|
import { useState } from 'react';
|
|
|
|
export function ProductGrid({ initial }: { initial: Product[] }) {
|
|
const [filter, setFilter] = useState('');
|
|
const visible = initial.filter(p => p.name.includes(filter));
|
|
return (
|
|
<>
|
|
<input value={filter} onChange={e => setFilter(e.target.value)} />
|
|
{visible.map(p => <Card key={p.id} {...p} />)}
|
|
</>
|
|
);
|
|
}
|
|
```
|
|
|
|
### Client Component 안 Server Component (children slot)
|
|
```tsx
|
|
// Layout.tsx (Client — needs onClick)
|
|
'use client';
|
|
export function Sidebar({ children }: { children: ReactNode }) {
|
|
return <aside onClick={...}>{children}</aside>;
|
|
}
|
|
|
|
// page.tsx (Server)
|
|
import { Sidebar } from './Sidebar';
|
|
import { ServerProfile } from './ServerProfile';
|
|
|
|
export default function Page() {
|
|
return (
|
|
<Sidebar>
|
|
<ServerProfile /> {/* Server component as children — OK */}
|
|
</Sidebar>
|
|
);
|
|
}
|
|
```
|
|
|
|
### Server Action 호출 (Client → Server mutation)
|
|
```tsx
|
|
'use client';
|
|
import { createPost } from './actions'; // 'use server' file
|
|
|
|
export function NewPostForm() {
|
|
return (
|
|
<form action={createPost}>
|
|
<input name="title" />
|
|
<button>Submit</button>
|
|
</form>
|
|
);
|
|
}
|
|
```
|
|
|
|
### Suspense + Streaming
|
|
```tsx
|
|
// page.tsx (Server)
|
|
import { Suspense } from 'react';
|
|
import { Comments } from './Comments';
|
|
|
|
export default function Page() {
|
|
return (
|
|
<>
|
|
<Article />
|
|
<Suspense fallback={<Skeleton />}>
|
|
<Comments /> {/* streamed in */}
|
|
</Suspense>
|
|
</>
|
|
);
|
|
}
|
|
```
|
|
|
|
## 매 결정 기준
|
|
| 상황 | Approach |
|
|
|---|---|
|
|
| Static rendering, data fetching | **Server Component** (default) |
|
|
| State / event / effect / browser API | **Client Component** |
|
|
| SEO + interactive (form) | Server shell + Client island |
|
|
| 매 entire page interactive (dashboard) | Mostly client, server outer layout |
|
|
|
|
**기본값**: 매 default Server Component — 매 boundary 를 leaf 에 push, 매 'use client' 매 minimum.
|
|
|
|
## 🔗 Graph
|
|
- 부모: [[React Server Components — 경계 의식]]
|
|
- 변형: [[Modern_Web_Rendering_and_Optimization|Server Components]] · [[Server Actions]]
|
|
- 응용: [[Hydration]] · [[Suspense]] · [[Streaming SSR]]
|
|
- Adjacent: [[Islands Architecture]] · [[Astro]]
|
|
|
|
## 🤖 LLM 활용
|
|
**언제**: interactivity 매 필요한 leaf component, browser-only API, 매 form / input control.
|
|
**언제 X**: data fetching 매 only, static content — Server Component 가 더 light.
|
|
|
|
## ❌ 안티패턴
|
|
- **Root layout 매 'use client'**: 매 entire app 매 client bundle — 매 RSC benefit 의 destruction.
|
|
- **Server-only data 매 props 로 큰 객체 pass**: 매 RSC payload bloat.
|
|
- **Client component 안 server-only import** (e.g., `fs`, `db`): 매 build error / leak risk.
|
|
- **Server Component 안 useState**: 매 build error — 매 boundary 의 misunderstanding.
|
|
|
|
## 🧪 검증 / 중복
|
|
- Verified (React docs RSC 2026, Next.js 15 App Router guide).
|
|
- 신뢰도 A.
|
|
|
|
## 🕓 Changelog
|
|
| 날짜 | 변경 |
|
|
|---|---|
|
|
| 2026-05-08 | Phase 1 |
|
|
| 2026-05-10 | Manual cleanup — 'use client' boundary + composition rules + Server Action |
|