Files
2nd/10_Wiki/Topics/Frontend/Client Components.md
T
koriweb d8a80f6272 chore(wiki): dangling 링크 canonical 정규화 (768파일/1200건)
이름만 다른(표기 변형) [[위키링크]]를 대상 문서의 canonical 제목으로 치환해
끊겼던 1,200개 링크를 연결. 제목/파일명 정규화 일치만 적용하고 별칭 매칭은
과병합 위험으로 제외(애매성 가드). 원본은 _link_reconcile_backup/ 에 백업.
도구: Datacollect/scripts/link_reconcile_apply.mjs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 12:24:15 +09:00

5.3 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-client-components Client Components 10_Wiki/Topics verified self
RSC Client Components
use client
none A 0.9 applied
react
nextjs
rsc
frontend
hydration
2026-05-10 pending
language framework
typescript 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

'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)

// 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} />;
}
// 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)

// 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)

'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

// 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

🤖 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