HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
💌
JJong’s Archive
/
Server Actions

Server Actions

생성 일시
Nov 25, 2024 04:18 AM
  • fetch, route 핸들러 필요 없이 api 처리하기(Next.js 13~)
  • POST method로만 처리됨. but 다른 메소드 요청 작업 가능! (비표준적인 설계이긴 함)
  • 클라이언트 컴포넌트에서 호출 가능
  • 사용 유형
      1. Form (대표적)
        1. import { handleSubmit } from './actions'; export default function FormComponent() { return ( <form action={handleSubmit}> <input type="text" name="name" placeholder="Enter your name" /> <button type="submit">Submit</button> </form> ); }
      1. 이벤트 핸들러
        1. 'use client'; import { handleAction } from './actions'; export default function ButtonComponent() { const handleClick = async () => { await handleAction('Hello, Server Action!'); }; return <button onClick={handleClick}>Call Server Action</button>; }
      1. useEffect 내부에서
        1. 'use client'; import { fetchData } from './actions'; export default function EffectComponent() { useEffect(() => { fetchData(); }, []); return <div>Fetching data...</div>; }
 

How To

  1. api 처리하는 비동기 함수(async), 즉 server action을 만듦
    1. 최상단에 “use server” ⇒ 서버에서만 작동되어야 함을 의미
    2. client component에서 : use server 함수를 쓸 수 X
      1. ⇒ 서버액션 함수를 파일로 분리
    3. 클.컴이 아니라면 인라인으로 서버액션 함수 쓸 수 있음
  1. form 속성에 action={서버액션} 속성 추가
    1. ⇒ submit 될 때 서버액션 실행
  1. server action에서 매개변수로 payload data를 받을 수 있음
    1. 서버액션의 매개변수(== data) 형식 : FormData
    2. 데이터.get(”input의 name속성 값”)
    3. 받으려면, input의 name 속성을 꼭 적용해줘야 함
export async function handleForm(formData: FormData) { await new Promise((resolve) => { setTimeout(resolve, 3000); }); const email = formData.get("email"); console.log(formData.get("email"), formData.get("password")); return email }
app/login/actions.ts
  • 서버와 통신 과정 비교 : API Routes vs Server Action
    • 서버와 통신 과정
      백엔드와 통신
      API Route
      Server Action
      1. 서버에게 요청 방식
      fetch(HTTP요청)
      fetch(HTTP요청)
      서버액션 함수 호출 (form은 action 속성으로)
      메소드
      fetch 할 때 명시
      fetch 할 때 명시
      자동으로 POST 요청 생성
      2. 서버측 코드 실행
      백엔드 코드 실행
      api/route.ts 에 핸들러 실행
      서버액션 함수 실행
  • 이벤트 핸들러(on~)을 쓰면 클.컴이 되어야 하는데, 클.컴에서는 db 조작 같은 서버 작업을 할 수 없으므로 이 때 서버액션을 사용.
    • ⇒ 그게 아니라면 db 조작을 굳이 서버액션에서 할 필요 x. 일반 함수에서 가능
  • 서버액션 내부에서 다른 HTTP 요청(fetch) 시, 모든 메서드 요청 가능

서버액션과 함께 쓰면 유용한 react 훅들

1. useFormStatus

useFormStatus ⇒ form action의 작업 상태를 알려주는 훅
  1. 사용하려면 “use client”
  1. action(어떤 액션인지), data, method, pending(로딩) 을 속성으로 제공
  1. 부모 action의 상태를 본다.
    1. ⇒ action form이 있는 곳에선 사용 X
      ⇒ form의 자식에서만(form 상태에 따라 변경되는 컴포넌트) 사용!
ex)
const FormButton = ({ text }: FormButtonProps) => { const { pending } = useFormStatus(); return ( <button disabled={pending} className="primary-btn h-10 disabled:bg-neutral-400 disabled:text-neutral-300 disabled:cursor-not-allowed" > {pending ? "Loading..." : text} </button> ); };
 
 

2. useFormState(~14) / useActionState(15~)

⇒ 서버액션을 실행 후 얻은 리턴값과, 서버액션을 실행할 수 있게하는 trigger를 제공
  1. 사용하려면 “use client”
  1. const [state, action] = useActionState(서버액션, 초기상태값)
    1. state : 서버액션 실행하고 얻은 return 값
    2. action(trigger) : 서버액션을 실행
      • 보통 초기상태 값으로 null을 주로
  1. 태그의 action 속성에 action을 넣기
    1. 실행할 때 useActionState에 이전 state, 즉 이전 return 값(혹은 초기값)이 인자에 넣어져 실행됨
    2. ⇒ 그러므로, 서버액션 함수의 매개변수에 prevState도 추가해줘야 함
ex)
"use server"; export async function handleForm(prevState: any, formData: FormData) { console.log("prevState >>>", prevState); ... return email; }
login/action.ts (서버액션 함수)
"use client"; ... import { handleForm } from "./actions"; const LoginPage = () => { const [state, action] = useActionState(handleForm, "null"); return ( .. <form action={action} className="gap-3 flex flex-col"> <FormInput type="email" name="email" placeholder="Email" required errorMessages={[state?.toString() ?? ""]} /> ...
login/page.tsx