일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- 클래스 속성
- 좋은글
- Python
- 파이썬 반복문
- python Django
- activate 오류
- Python Class
- 다중조건문
- Kotlin 조건문
- 자바 기본타입
- NextJs
- 넥스트js
- git
- 파이썬 제어문
- Kotlin If
- github
- 파이썬
- Kotlin 클래스
- 장고 가상환경
- Kotlin Class
- 도전
- 강제 타입변환
- 파이썬 클래스
- 성공
- Kotlin 클래스 속성정의
- 파이썬 장고
- 희망
- Kotlin else if
- django virtualenv
- Variable declaration
Archives
- Today
- Total
키모스토리
#9. Create Blog Posts 본문
반응형
로그인 여부에 따른 Navigation 수정 (글작성) - /posts/create
import getAuthUser from "@/lib/getAuthUser";
import NavLink from "./NavLink"
import { logout } from "@/actions/auth";
export default async function Navigation() {
const authUser = await getAuthUser();
console.log("authUser=", authUser);
return (
<nav>
<NavLink label="Home" href="/" />
{authUser ?
(
<div className="flex items-center">
<NavLink label="New Post" href="/posts/create" />
<NavLink label="Dashboard" href="/dashboard" />
<form action={logout}>
<button className="nav-link">Logout</button>
</form>
</div>
) :
(
<div className="flex items-center">
<NavLink label="Register" href="/register" />
<NavLink label="Login" href="/login" />
</div>
)}
</nav>
)
}
블로그 글작성페이지 (BlogForm 컴포넌트로 분리작성)
formaction으로 db처리를 위해 action처리
/src/app/posts/create/page.jsx
"use client"
import { createPost } from "@/actions/posts";
import BlogForm from "@/components/BlogForm";
export default function CreatePost() {
return (
<div className="container w-1/2">
<h1 className="title">Create a new post</h1>
<BlogForm handler={createPost} />
</div>
);
}
BlogForm 컴포넌트
form의 action (DB입력) 처리를 위해 createPost
/src/components/BlogForm.jsx
"use client";
import { useActionState } from "react";
export default function BlogForm({handler}) {
const [state, action, isPending] = useActionState(handler, undefined);
return (
<form action={action} className="space-y-4">
<div>
<label htmlFor="title">Title</label>
<input type="text" name="title" defaultValue={state?.title} />
{state?.errors?.title && (
<p className="error">{state.errors.title}</p>
)}
</div>
<div>
<label htmlFor="content">Content</label>
<textarea name="content" rows={10} defaultValue={state?.content} />
{state?.errors?.content && (
<p className="error">{state.errors.content}</p>
)}
</div>
<button disabled={isPending} className="btn-primary w-full">
{isPending ? "Loading..." : "Submit"}
</button>
</form>
);
}
글작성 처리 action
/src/actions/posts.js
"use server";
import { getCollection } from "@/lib/db";
import getAuthUser from "@/lib/getAuthUser";
import { BlogPostSchema } from "@/lib/rules";
import { ObjectId } from "mongodb";
import { redirect } from "next/navigation";
// 블로그 글관리 액션정의
export async function createPost(state, formData) {
// 로그인 여부
const authUser = await getAuthUser();
if (!authUser) redirect("/login");
const title = formData.get("title");
const content = formData.get("content");
// 유효성 검사 규칙은 src/lib/rules.js에 정의되어 있습니다.
const validatedFields = BlogPostSchema.safeParse({
title,
content,
});
// 유효성 검사에 실패한 경우, 에러 메시지를 반환합니다.
// 에러 메시지는 src/lib/rules.js에 정의된 규칙에 따라 다르게 표시됩니다.
if (!validatedFields.success) {
return {
errors: validatedFields.error.flatten().fieldErrors,
title: title,
content: content,
};
}
// Save to DB
try {
const postsCollection = await getCollection("posts");
if( !postsCollection) {
return { errors: { title: "Server error!" } };
}
await postsCollection.insertOne({
title: validatedFields.data.title,
content: validatedFields.data.content,
userId: ObjectId.createFromHexString(authUser.userId)
});
} catch (error) {
return { errors: { title: error.message } };
}
redirect("/posts");
}
글작성 폼 validate
/src/lib/rules.js
// 블로그 등록 폼 검사합니다.
export const BlogPostSchema = z
.object({
title: z
.string()
.min(1, { message: "Title field is required." })
.max(100, { message: "Title can't be more than 100 characters." })
.trim(),
content:
z.string()
.min(1, { message: "Content field is required." }).trim(),
});
반응형
'Web Devlopment > Next-Blog Project' 카테고리의 다른 글
#10. Read Blog Posts (home) (0) | 2025.04.05 |
---|---|
#8. Auth & Guest Links (0) | 2025.04.05 |
#7. Login (0) | 2025.04.05 |
#6. Active Links (0) | 2025.04.05 |
#5. server-only (0) | 2025.04.05 |