React Server Components(RSC)는 서버에서만 실행되는 React 컴포넌트로, 클라이언트에 JS를 전송하지 않고 서버에서 직접 데이터를 가져와 렌더링한다. Next.js 13+ App Router의 기본 컴포넌트다.
Server Component vs Client Component
Server Component (기본):
- 서버에서 실행, JS 번들에 포함 안 됨
- 직접 DB, 파일 시스템, API 접근
- useState, useEffect, 이벤트 핸들러 불가
- async/await 사용 가능
Client Component ('use client' 지시어):
- 서버 + 클라이언트 모두에서 실행
- 상태(useState), 효과(useEffect), 이벤트 사용
- 브라우저 API 접근 가능
- JS 번들에 포함됨
규칙:
Server → Client 컴포넌트 자식으로 가능
Client → Server 컴포넌트 import 불가 (props로 전달은 가능)
예시 (Next.js App Router)
tsx
// app/posts/page.tsx (Server Component - 기본값)
// 'use server' 불필요 - 기본이 서버 컴포넌트
import { PostList } from './PostList';
import { LikeButton } from './LikeButton'; // Client Component
async function getPosts() {
// 서버에서 직접 DB 조회
const posts = await db.query('SELECT * FROM posts ORDER BY created DESC');
return posts;
}
export default async function PostsPage() {
const posts = await getPosts(); // async/await 가능
return (
<main>
{posts.map(post => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.content}</p>
{/* Client Component: 인터랙티브 버튼 */}
<LikeButton postId={post.id} initialLikes={post.likes} />
</article>
))}
</main>
);
}
// app/posts/LikeButton.tsx (Client Component)
'use client';
import { useState } from 'react';
export function LikeButton({ postId, initialLikes }) {
const [likes, setLikes] = useState(initialLikes);
return (
<button onClick={() => setLikes(l => l + 1)}>
좋아요 {likes}
</button>
);
}
Server Actions
tsx
// 서버 액션: 클라이언트에서 서버 함수 직접 호출
'use server'; // 파일 전체 또는 함수에 적용
export async function createPost(formData: FormData) {
const title = formData.get('title') as string;
await db.execute('INSERT INTO posts(title) VALUES(?)', [title]);
revalidatePath('/posts'); // 캐시 무효화
}
// 클라이언트에서 사용
import { createPost } from './actions';
export default function NewPostForm() {
return (
<form action={createPost}>
<input name="title" />
<button type="submit">작성</button>
</form>
);
}
관련 문서