서버 액션

정호성·2025년 3월 12일

Next.js

목록 보기
15/18

서버 액션 (Server Actions)?

서버 액션은 클라이언트에서 직접 서버 함수를 호출할 수 있도록 도와주는 기능이다.
기존의 API 라우트 또는 서버리스 함수 없이도 폼 제출, 데이터 처리, 데이터베이스 업데이트 등을 간결하게 구현할 수 있다.


사용법

서버 액션은 서버에서 실행되는 비동기 함수이며, use server 디렉티브를 통해 선언할 수 있다.
이를 통해 클라이언트에서 직접 호출 가능하다.

function ReviewEditor() {
    async function createReviewAction(formData: FormData) {
        'use server'; // 'use server' 지시자로 서버액션 선언
        const content = formData.get('content')?.toString();
        const author = formData.get('author')?.toString();

        console.log(content, author);
    }

    return (
        <section>
            <form action={createReviewAction}>
                <input name="content" placeholder="리뷰 내용" />
                <input name="author" placeholder="작성자" />
                <button type="submit">작성하기</button>
            </form>
        </section>
    );
}

폼을 제출하면 서버에서 createReviewAction 함수가 실행되고, 클라이언트는 응답을 받아 UI를 갱신할 수 있다.


서버 액션의 특징과 장점

  1. API 라우트 없이 데이터 처리
    기존에는 데이터를 처리하려면 /api/route.ts를 생성해야 했지만, 서버 액션을 사용하면 서버에서 직접 데이터를 처리할 수 있다.

  2. 클라이언트에서 직접 서버 함수 호출
    기존의 API 요청(fetch, axios) 없이, 클라이언트에서 서버 함수를 직접 호출 가능하다.

  3. 보안성 강화
    서버에서만 실행되므로 클라이언트에서 코드를 확인할 수 없으며, 환경 변수(process.env) 접근이 가능하다.

결론적으로, 서버 액션은 API 라우트 없이 서버에서 직접 데이터를 처리할 수 있는 강력한 기능이다.
간결한 코드로 서버 요청을 처리할 수 있어 폼 제출, 데이터베이스 업데이트, 보안이 필요한 로직 실행에 유용하다.


최신 데이터 반영하기

서버 액션을 사용할 때, Next.js는 기본적으로 페이지를 정적으로 캐시하여 성능을 최적화한다. 하지만, 데이터가 변경되었을 때 즉시 최신 데이터를 반영하려면 revalidatePath 함수를 사용해야 한다.

revalidatePath(경로)를 호출하면, 해당 경로의 정적 캐시를 무효화하고 새로운 데이터를 불러오도록 강제 갱신할 수 있다.

📌 revalidatePath 사용 예시

사용자를 추가한 후, 홈 페이지(/)의 캐시를 무효화하여 최신 데이터가 즉시 반영되도록 한다.

// app/actions.ts
"use server";
import { revalidatePath, revalidateTag } from 'next/cache';

export async function createReviewAction(formData: FormData) {
    const bookId = formData.get('bookId')?.toString();
    const content = formData.get('content')?.toString();
    const author = formData.get('author')?.toString();

    if (!bookId || !content || !author) {
        return;
    }

    try {
        const response = await fetch(
            `${process.env.NEXT_PUBLIC_API_SERVER_URL}/review`,
            {
                method: 'post',
                body: JSON.stringify({ bookId, content, author }),
            },
        );


        // 1. 특정 주소에 해당하는 페이지만 재검증
        revalidatePath(`/book/${bookId}`);
        
        // 2. 특정 경로의 모든 동적 페이지를 재검증
        revalidatePath('/book/[id]', 'page');
       
        // 3. 특정 레이아웃을 갖는 모든 페이지 재검증
        revalidatePath('/(with-searchbar)', 'layout');
        
        // 4. 모든 데이터 재검증
        revalidatePath('/', 'layout');

        // 5. 특정 태그를 갖는 데이터 캐시 재검증
        revalidateTag(`review-${bookId}`);
    } catch (err) {
        console.error(err);
        return;
    }
}

🛠 revalidatePath를 사용해야 하는 경우

  1. ✅ 데이터가 변경된 후 즉시 반영해야 할 때
  2. ✅ 서버 액션에서 데이터베이스 업데이트 후 화면을 갱신할 때
  3. ✅ 정적 페이지(SSG)에서 특정 경로의 캐시를 강제로 무효화할 때

⚠️ revalidatePath 사용 시 주의점

  1. 서버 측에서만 호출 가능 (클라이언트 컴포넌트에서는 사용할 수 없음)
  2. 해당하는 페이지의 캐시를 전부 무효화 (풀 라우트 캐시도 삭제)
  3. 경로 단위로 무효화 (특정 컴포넌트만 갱신할 수 없음)
  4. revalidatePath("/")는 루트 페이지 전체를 다시 렌더링하므로, 성능 영향을 고려해야 함
profile
👨🏻‍💻 Front-End Developer

0개의 댓글