
src/lib/posts.ts
백엔드 연동 전에 우선 사용할 더미 데이터!
export const posts = [
{
slug: "start-blog",
title: "블로그 시작! 계획과 구조",
content: `...`,
},
{
slug: "why-next",
title: "왜 Next일까?",
content: `...`,
},
];
export function getPostBySlug(slug: string) {
return posts.find((post) => post.slug === slug);
}
두개의 데이터를 넣어줬고 slug로 객체를 찾아 반환하는 getPostBySlug도 만들어줬다.
app/api/posts/[slug]/route.ts
import { NextResponse } from "next/server";
import { getPostBySlug } from "@/lib/posts";
export async function GET(
req: Request,
{ params }: { params: { slug: string } }
) {
const post = getPostBySlug(params.slug);
if (!post) {
return NextResponse.json(null, { status: 404 });
return NextResponse.json(post);
}
나중에 DB 연결 하면 수정 예정
NextResponse:
Response 객체를 확장한 Next 전용 응답 유틸리티! Next에서 쿠키 설정, 리다이렉트, rewrite 등 확장이 가능하다고 한다.
src/app/posts/[slug]/page.tsx
URL에서 slug 값을 받아서 해당 slug에 해당하는 게시글을 요청해서에서 가져오고, Markdown를 파싱하고 HTML 형태로 브라우저에 렌더링하기!
import { marked } from "marked";
import { notFound } from "next/navigation";
export default async function PostPage({
params,
}: {
params: { slug: string };
}) {
const res = await fetch(`http://localhost:3000/api/posts/${params.slug}`, {
cache: "no-store",
});
if (!res.ok) return notFound();
const post = await res.json();
const html = marked(post.content);
return (
<article className="prose prose-invert prose-lg md:prose-xl lg:prose-xl mx-auto px-6 py-10">
<h1 className="text-center">{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: html }} />
</article>
);
}
요청해서 받아온 걸 파싱해서 post의 content를 marked 라이브러리로 HTML 문자열로 바꿔주고 dangerouslySetInnerHTML로 렌더링
cache: "no-store":
기본적으로 Next.js는 페이지를 캐싱하는데 이게 처음으로 페이지를 들어가면 다음 요청 때 까지 저장둬서 속도는 빨라짐. 근데 내가 만드는건 블로그니까. 수정이되고 하면 항상 최신의 글을 보여줘야 하니까 no-store가 맞다. 이렇게 하면 매번 API를 새로 호출해서 최신 데이터를 가져온다.
그리고 이부분은 지금만 이렇게 해두고 나중에 ISR로 일정 주기마다 HTML을 재생성하게 해주면 이부분을 지워도 될 것 같다.
prose:
Tailwind Typography 플러그인을 사용해서 예쁘게 HTML 스타일도 적용시킴
http://localhost:3000/posts/why-next로 접속하면 해당되는 포스트가 보인다.

이제 이 포스트 상세 페이지를 메인 페이지에서 연결시키면 될 것 같다. 다음!