-
Notifications
You must be signed in to change notification settings - Fork 5
React Server Component와 Server Action로 CRUD 구현
먼저 Server Component를 사용하여 게시글 목록을 조회하는 기능을 구현합니다.
// app/page.js
async function getPosts() {
// 데이터베이스에서 게시글 목록을 가져오는 로직
const posts = await db.post.findMany();
return posts;
}
export default async function PostList() {
const posts = await getPosts();
return (
<div>
<h1>게시글 목록</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
}
Server Action을 사용하여 게시글 작성 기능을 구현합니다.
// app/actions.js
'use server';
export async function createPost(formData) {
const title = formData.get('title');
const content = formData.get('content');
// 데이터베이스에 게시글 저장
await db.post.create({ data: { title, content } });
}
// app/create-post.js
import { createPost } from './actions';
export default function CreatePost() {
return (
<form action={createPost}>
<input type="text" name="title" placeholder="제목" required />
<textarea name="content" placeholder="내용" required></textarea>
<button type="submit">게시글 작성</button>
</form>
);
}
게시글 수정을 위한 Server Action을 구현합니다.
// app/actions.js
'use server';
export async function updatePost(formData) {
const id = formData.get('id');
const title = formData.get('title');
const content = formData.get('content');
await db.post.update({
where: { id },
data: { title, content },
});
}
// app/edit-post.js
import { updatePost } from './actions';
export default async function EditPost({ id }) {
const post = await db.post.findUnique({ where: { id } });
return (
<form action={updatePost}>
<input type="hidden" name="id" value={post.id} />
<input type="text" name="title" defaultValue={post.title} required />
<textarea name="content" defaultValue={post.content} required></textarea>
<button type="submit">게시글 수정</button>
</form>
);
}
마지막으로 게시글 삭제를 위한 Server Action을 구현합니다.
// app/actions.js
'use server';
export async function deletePost(formData) {
const id = formData.get('id');
await db.post.delete({ where: { id } });
}
// app/delete-post.js
import { deletePost } from './actions';
export default function DeletePost({ id }) {
return (
<form action={deletePost}>
<input type="hidden" name="id" value={id} />
<button type="submit">게시글 삭제</button>
</form>
);
}
이제 모든 CRUD 기능을 통합한 예제를 만들어보겠습니다.
// app/page.js
import CreatePost from './create-post';
import EditPost from './edit-post';
import DeletePost from './delete-post';
async function getPosts() {
const posts = await db.post.findMany();
return posts;
}
export default async function PostList() {
const posts = await getPosts();
return (
<div>
<h1>게시글 관리</h1>
<CreatePost />
<ul>
{posts.map((post) => (
<li key={post.id}>
<h3>{post.title}</h3>
<p>{post.content}</p>
<EditPost id={post.id} />
<DeletePost id={post.id} />
</li>
))}
</ul>
</div>
);
}
이 예제에서는 React Server Component를 사용하여 게시글 목록을 렌더링하고, Server Action을 사용하여 게시글 생성, 수정, 삭제 기능을 구현했습니다[1][2]. Server Component는 서버에서 데이터를 가져와 렌더링하며, Server Action은 클라이언트에서 서버의 함수를 호출하여 데이터를 변경합니다[3][4].
이 접근 방식을 사용하면 서버에서 직접 데이터를 처리하므로 보안성이 향상되고, 클라이언트 측 JavaScript 번들 크기를 줄일 수 있습니다. 또한 Server Action을 사용하면 폼 제출 시 JavaScript가 로드되지 않았거나 비활성화된 경우에도 기본적인 기능이 작동하므로 점진적 향상(progressive enhancement)을 지원합니다[5].
Citations: [1] https://react.dev/reference/rsc/server-actions [2] https://nextjs.org/docs/13/app/building-your-application/data-fetching/server-actions-and-mutations [3] https://www.reddit.com/r/nextjs/comments/1d6hd3q/what_the_point_of_server_actions_with_server/ [4] https://react.dev/reference/rsc/use-server [5] https://nextjs-ko.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations [6] https://velog.io/@shinhw371/Next.js-Server-Action [7] https://bandal.dev/React/react-hook-form-with-nextjs-server-actions [8] https://velog.io/@ckstn0777/Next.js-13.4-Server-Actions%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C