서버에서 비동기 코드를 실행할 수 있도록 해주는 기능입니다. 서버 액션을 사용하면, API 엔드포인트를 생성하지 않고도 컴포넌트 내에서 비동기 함수를 직접 정의할 수 있습니다.
함수 안 최상단 use server
를 선언하고, async
키워드를 붙이면 서버에서 동작하는 Server Action이 됩니다.
async function UploadPost() {
'use server'
//...
}
한 파일 내에 여러 Server Action을 정의하는 경우 파일 최상단에 use server
를 한번만 선언하면됩니다.
'use server'
async function UploadPost() {
//...
}
async function DeletePost() {
//...
}
<br>
Server Action 사용을 위해 로컬 데이터베이스 사용을 위해 better-sqlite3
라이브러리를 사용하였습니다.
"use server";
const sql = require("better-sqlite3");
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
const db = sql("posts.db");
export const getPosts = async () => {
await new Promise((res) => setTimeout(res, 2000));
return db.prepare("SELECT * FROM posts").all();
};
export async function upload(formData: FormData) {
const title = formData.get("title") as string | null;
const content = formData.get("content") as string | null;
let errors = [];
if (!title || title.trim().length === 0) {
errors.push("Title is required.");
}
if (!content || content.trim().length === 0) {
errors.push("Content is required.");
}
if (errors.length > 0) {
return { errors };
}
const post = {
title: formData.get("title"),
content: formData.get("content"),
};
await savePost(post);
revalidatePath("/posts");
redirect("/posts");
}
export async function savePost(post: {
title: FormDataEntryValue | null;
content: FormDataEntryValue | null;
}) {
db.prepare(
`
INSERT INTO posts
(title, content)
VALUES (
@title,
@content
)
`
).run(post);
}
form action를 통해 Server Action를 전달해주어 Server Action를 적용합니다.
💡 from action