오늘도 회사는 평화롭지 않았다.
아직 많이 남았지만... 하루종일 터진일을 매꾸다가 돌아왔다.
이게 맞나 싶은데... 준비를 더 하는게 맞는거 같다.
어찌되었건...
오늘은 폼 전송에 대해 학습중이다.
'use client'를 사용하여 폼을 전송하면 쉽게 개발이 이루어진다.
하지만 서버에서 실행되어야 하는 로직들이 존재한다.
이를 처리하는 부분에 대해 학습한다.
'use client';
import { useFormState } from "react-dom";
import FormSubmit from "@/components/form-submit";
export default function PostForm({action}) {
const [state, formAction] = useFormState(action, {});
return (
<>
<h1>Create a new post</h1>
<form action={formAction}>
....
</form>
</>
);
}
'use client';
import { useFormStatus } from "react-dom";
export default function FormSubmit() {
const status = useFormStatus();
console.log("Form status:", status);
if (status.pending) {
return <p>Creating post...</p>;
}
return (
<>
<button type="reset">Reset</button>
<button>Create Post</button>
</>
);
}
클라이언트 쪽 소스이다.
여기서 중요한 부분만 몇줄 뽑아보자.
이 코드가 핵심이다.
useFormState는 useActionState로 이름이 변경되었다.
useFormState(action, {});
action은 폼이 제출될 서버 액션 또는 비동기 함수이며, 이 함수는 (prevState, formDate)를 인자로 받는다.
{}는 state의 초기값이다.
const [state, formAction]
state는 액션이 실행된 후 반환된 결과값이다. 성공, 에러, 수정된 데이터 등이 담긴다.
formAction은 <form action={formAction}> 과 같이 폼 요소에 직접 전달할 실행 함수이다.
단 할줄의 코드지만 이해하기가 쉽지 않다.
이해를 해보자...
<form action={formAction}> 을 통해 formAction이 실행된다.
브라우저는 폼에 입력된 값을 formData 객체로 만든다.
이 데이터가 우리가 정의한 action함수로 전달된다.
action 함수는 state와 formData를 가지고 처리를 한다.
export default function NewPostPage() {
async function createPost(prevState, formData) {
"use server";
const title = formData.get("title");
const image = formData.get("image");
const content = formData.get("content");
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){
logger.error("Validation errors:", { errors });
return {errors};
}
logger.info("Creating post with data:", { title, image, content });
await storePost({
imageUrl: '',
title,
content,
userId: 1
});
redirect('/feed'); // Redirect to the homepage after creating the post
}
return <PostForm action={createPost} />;
}
위 소스를 좀더 간단하게 만들어 보겠다.
export default function NewPostPage() {
async function createPost(prevState, formData) {
"use server";
const title = formData.get("title");
const image = formData.get("image");
const content = formData.get("content");
.....
return <PostForm action={createPost} />;
}
PostForm action에 실제로 action이 일어나는 코드를 전달한다.
실제 처리는 server에서 createPost(...)에서 일어나는 것이다.
createPost에서 반환하는 값이 다시 useFormState로 돌아오고, 상태정보고 state에 들어간다.
여기서 이해가 가지 않는다.
자연스럽다. 나도 이해가 가지 않았다.
이벤트 방식인거 같았다.
export function useFormState<State>(
action: (state: Awaited<State>) => State | Promise<State>,
initialState: Awaited<State>,
permalink?: string,
): [state: Awaited<State>, dispatch: () => void, isPending: boolean];
위 코드를 이해해야 하는데...
아직 저걸 이해할 정도는 되지 않는것 같다.
상세 소스는 추후에 다시 한번 깨부수기로 하고, 이벤트로 이어지는 걸로 이해하고 오늘은 넘어가자
아직 갈 길이 멀다...
'진심 코딩' 카테고리의 다른 글
| [NextJS] 20260406 동적 라우트 안에 중첩된 라우트, 인터셉팅 라우팅 (0) | 2026.04.06 |
|---|---|
| [NextJS] 20260405 Catch-all 라우팅 구성 (0) | 2026.04.05 |
| [NextJS] 20260405 병렬라우팅, 캐시, metadata (0) | 2026.04.05 |
| [NextJS] 260404 폼 제출 상태 확인 (0) | 2026.04.04 |
| [NEXTj] 2일차 일지 - mysql 연동 설정 (0) | 2026.04.02 |