본문 바로가기
FrontEnd/Next.js

form에서 server action 다루기

by 위그든씨 2024. 6. 15.

https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations

form action에서 server action을 하기 위해서는 비동기 함수를 넘겨주면서 use server를 입력해주면 됨

export default function Page() {
    async function createInvoice(formData: FormData) {
        'use server';

        const rawFormData = {
            customerId: formData.get('customerId'),
            amount: formData.get('amount'),
            status: formData.get('status'),
        };
        console.log(rawFormData);
        // mutate data
        // revalidate cache
    }

    return (
        <div className="flex justify-center items-center max-w-xl ">
            <form className="flex flex-col space-y-4" action={createInvoice}>
                <input className="border" type="text" name="customerId" />
                <input className="border" type="text" name="amount" />
                <input className="border" type="text" name="status" />
                <button type="submit">submit</button>
            </form>
        </div>
    );
}

만약 클라이언트 쪽에서 서버 액션을 다뤄야한다면 해당 컴포넌트를 분리해야 할 필요가 있다.

import { createInvoice } from './_action';
import ClientPage from './_components/clientPage';

export default function Page() {
    return (
        <div className="flex justify-center items-center max-w-xl ">
            <ClientPage createInvoice={createInvoice} />
        </div>
    );
}
'use client';

interface ClientPageProps {
    createInvoice: (data: FormData) => void;
}

export default function ClientPage({ createInvoice }: ClientPageProps) {
    return (
        <form className="flex flex-col space-y-4" action={createInvoice}>
            <input className="border" type="text" name="customerId" />
            <input className="border" type="text" name="amount" />
            <input className="border" type="text" name="status" />
            <button type="submit">submit</button>
        </form>
    );
}
'use server';

export async function createInvoice(formData: FormData) {
    const rawFormData = {
        customerId: formData.get('customerId'),
        amount: formData.get('amount'),
        status: formData.get('status'),
    };
    console.log(rawFormData);
    // mutate data
    // revalidate cache
}

만약 server action을 요하는 함수에서 FormData이외 props가 필요할 경우 아래처럼 코드 짜주기

// server action
'use server';

export async function createInvoice(userId: string, data: FormData) {
    console.log(data);
    console.log(userId);
    // mutate data
    // revalidate cache
}


// clientComponent.tsx
'use client';

import { createInvoice } from '../_action';

export default function ClientPage() {
    const userId = 'someUserId'; // Replace with actual user ID fetching logic
    const createInvoiceWithUserId = createInvoice.bind(null, userId);

    return (
        <form
            className="flex flex-col space-y-4"
            action={createInvoiceWithUserId}
        >
            <input className="border" type="text" name="customerId" />
            <input className="border" type="text" name="amount" />
            <input className="border" type="text" name="status" />
            <button type="submit">submit</button>
        </form>
    );
}

물론 아래처럼 코드를 짜도 됨.

action={(d) => createInvoice('someUserId', d)}