ํฐ์คํ ๋ฆฌ ๋ทฐ
๐ Next.js App Router์์ ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ ์์ ๊ฐ์ด๋
octo54 2025. 4. 18. 11:22๐ Next.js App Router์์ ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ ์์ ๊ฐ์ด๋
Next.js App Router์์๋ ๊ธฐ์กด REST API๋ API Route๋ฅผ ๋ง๋ค์ง ์๊ณ ๋, Server Actions๋ฅผ ์ฌ์ฉํด ์๋ฒ์์ ์ง์ ๋ฐ์ดํฐ๋ฅผ ์
๋ฐ์ดํธํ ์ ์์ต๋๋ค.
์ด ๋ฐฉ์์ ์ฝ๋๋์ ์ค์ด๊ณ ๋ณด์์ฑ์ ๋์ด๋ฉฐ, ์๋ฒ์์ ์ฒ๋ฆฌ๋ ๊ฒฐ๊ณผ๋ฅผ ์ฆ์ UI์ ๋ฐ์ํ ์ ์๋ ์ฅ์ ์ด ์์ต๋๋ค.
โ Server Action์ด๋?
'use server' ๋๋ ํฐ๋ธ๋ฅผ ์ฌ์ฉํ๋ฉด ํด๋น ํจ์๋ ํด๋ผ์ด์ธํธ์์ ํธ์ถ๋๋๋ผ๋ ์๋ฒ์์ ์คํ๋๋ ํจ์๋ก ๋ณํ๋ฉ๋๋ค.
// app/lib/actions.ts
'use server';
export async function createPost(formData: FormData) {
const title = formData.get('title');
const content = formData.get('content');
// ์ฌ๊ธฐ์ DB INSERT ๋ก์ง ์ถ๊ฐ
}
๋๋ ์๋ฒ ์ปดํฌ๋ํธ ๋ด๋ถ ํจ์๋ก๋ ์ ์ธ ๊ฐ๋ฅํฉ๋๋ค:
// app/page.tsx
export default function Page() {
async function submit(formData: FormData) {
'use server';
// DB ์ ์ฅ
}
return <form action={submit}>...</form>;
}
๐งพ HTML <form>์์ Server Action ํธ์ถํ๊ธฐ
// app/posts/create-form.tsx
import { createPost } from '@/app/lib/actions';
export default function CreateForm() {
return (
<form action={createPost}>
<input type="text" name="title" placeholder="์ ๋ชฉ" />
<textarea name="content" placeholder="๋ด์ฉ" />
<button type="submit">์์ฑ</button>
</form>
);
}
- form์ action ์์ฑ์ Server Action์ ์ฐ๊ฒฐ
- form ๋ฐ์ดํฐ๋ฅผ FormData ํํ๋ก ์๋ ์ ๋ฌ
๐ฑ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์ Server Action ํธ์ถ
ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์๋ formAction ์์ฑ์ ์ฌ์ฉํฉ๋๋ค.
'use client';
import { createPost } from '@/app/lib/actions';
export function SubmitButton() {
return <button formAction={createPost}>๋ฑ๋ก</button>;
}
- formAction์ ๋ฒํผ ํด๋ฆญ ์ ์ง์ ๋ Server Action์ ํธ์ถ
- type="submit" ๋ฒํผ๊ณผ ์ ์ฌํ์ง๋ง ํผ ์ธ๋ถ์์๋ ์ฌ์ฉ ๊ฐ๋ฅ
โป๏ธ ์บ์ ๋ฌดํจํ + ๋ฆฌ๋๋ ์ ์ฒ๋ฆฌ
๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋ ํ ํน์ ํ์ด์ง์ ์บ์๋ฅผ ๋ค์ ๋ถ๋ฌ์ค๊ณ , ์ฌ์ฉ์ ๊ฒฝ๋ก๋ฅผ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
'use server';
import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';
export async function createPost(formData: FormData) {
// DB ์ ์ฅ ๋ก์ง ์คํ
revalidatePath('/posts'); // ๋ชฉ๋ก ํ์ด์ง ์บ์ ๋ฌดํจํ
redirect('/posts'); // /posts ํ์ด์ง๋ก ์ด๋
}
- revalidatePath: ์ง์ ๊ฒฝ๋ก์ ์๋ฒ ์บ์๋ฅผ ๋ฌดํจํํ์ฌ ์ต์ ๋ฐ์ดํฐ๋ก ์ฌ์์ฒญ
- redirect: ์๋ฒ์์ ๋ฆฌ๋๋ ์ ์ํ
โ ๏ธ ์๋ฌ ํธ๋ค๋ง๋ ํ์
Server Action ๋ด๋ถ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ผ๋ฏ๋ก try/catch ์ฒ๋ฆฌ๋ก ๋ฐฉ์ด ์ฝ๋๋ฅผ ์์ฑํด์ผ ํฉ๋๋ค.
'use server';
export async function createPost(formData: FormData) {
try {
const title = formData.get('title');
// DB ์ ์ฅ ๋๋ ์ธ๋ถ ์์ฒญ
} catch (error) {
console.error('์๋ฌ ๋ฐ์:', error);
}
}
๐งช ๊ฐ๋จํ ์ค์ ๊ตฌ์กฐ ์์
app/
โโโ lib/
โ โโโ actions.ts # Server Action ์ ์
โโโ posts/
โ โโโ create-form.tsx # <form> ์ ์
โ โโโ page.tsx # ํ์ด์ง ์ปดํฌ๋ํธ
โ ์์ฝ ์ ๋ฆฌ
๊ธฐ๋ฅ ์ฌ์ฉ๋ฒ
Server Action ์์ฑ | 'use server' ๋๋ ํฐ๋ธ ์ฌ์ฉ |
form์์ ํธ์ถ | <form action={ํจ์}> ์ฌ์ฉ |
ํด๋ผ์ด์ธํธ ๋ฒํผ์์ ํธ์ถ | <button formAction={ํจ์}> ์ฌ์ฉ |
์บ์ ๋ฌดํจํ | revalidatePath('/url') |
๋ฆฌ๋๋ ์ | redirect('/target') |
์๋ฌ ์ฒ๋ฆฌ | try/catch ๊ตฌ์กฐ๋ก ์์ ํ๊ฒ |
Next.js, Server Actions, ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ, App Router, FormData, ์บ์ ๋ฌดํจํ, ๋ฆฌ๋๋ ์ , ํด๋ผ์ด์ธํธ ํธ์ถ, ์๋ฒ ํจ์, SEO ์ต์ ํ 10๊ฐ
'framework > NextJS' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
- Total
- Today
- Yesterday
- ์น๊ฐ๋ฐ
- Ktor
- SEO์ต์ ํ
- ๊ด๋ฆฌ์
- kotlin
- ๋ฐฑ์๋
- seo ์ต์ ํ 10๊ฐ
- llm
- nextJS
- NestJS
- fastapi
- ํ๋ก ํธ์๋
- CI/CD
- ๊ฐ๋ฐ๋ธ๋ก๊ทธ
- Docker
- ๋ฐฑ์๋๊ฐ๋ฐ
- nodejs
- github
- Prisma
- REACT
- rag
- Next.js
- Webpack
- ์ค๋งํธ ์ปจํธ๋ํธ
- AI ์๋ํ
- PostgreSQL
- AI์ฑ๋ด
- LangChain
- gatsbyjs
- App Router
์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
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 |