Link ์ปดํฌ๋ํธ๋ ์ ๋ง ํธ๋ฆฌํ๊ฒ ์ฌ์ฉ ํ ์ ์๋ค. href์ ๊ฒฝ๋ก๋ง ๋ฃ์ด์ฃผ๋ฉด ๊ทธ ํ์ด์ง๋ฅผ ๋ฏธ๋ฆฌ ๋ถ๋ฌ์์ค์(prefetching) ํด๋ฆญํ์ ๋ ๋ฐ๋ก ์ด๋ํ ์ ์์import Link from 'next/link'
export default function Navigation() {
return (
<nav>
<Link href="/">ํ</Link>
<Link href="/about">์๊ฐ</Link>
</nav>
)
}
Next.js 13๋ถํฐ๋ ์ํฌํธ ๊ฒฝ๋ก๊ฐ ๋ฐ๋์๋ค (next/navigation)
import { useRouter } from 'next/navigation'
export default function MyButton() {
const router = useRouter()
return (
<button onClick={() => router.push('/dashboard')}>
๋์๋ณด๋๋ก ์~โจ
</button>
)
}
router.push('/path') - ์ ํ์ด์ง๋ก ์ด๋, router.replace('/path') - ํ์คํ ๋ฆฌ ๋จ๊ธฐ์ง ์๊ณ ์ด๋router.back(), router.forward() - ๋ธ๋ผ์ฐ์ ํ์ดํ ๋ฒํผ๊ณผ ๊ฐ์ ํจ๊ณผrouter.refresh() - ํ์ด์ง๋ฅผ ์๋ก๊ณ ์นจํ์ง๋ง ์ํ๋ ์ ์งprefetch ๋ฉ์๋๋ก ์ฌ์ฉ์๊ฐ ๊ณง ๋ฐฉ๋ฌธํ ๊ฒ ๊ฐ์ ํ์ด์ง ๋ฏธ๋ฆฌ ์ค๋นํด๋๊ธฐapp ํด๋ ์์ ํด๋ ๋ง๋ค๊ณ route.ts ํ์ผ ํ๋ ์ถ๊ฐ// app/api/hello/route.ts
export async function GET() {
// ์ฌ๊ธฐ์ ๋ฌด์จ ์์
์ด๋ ํ ์ ์์!
return Response.json({ message: '์๋
ํ์ธ์!' })
}
// ์๋ฒ ์ก์
์ ์ - ์ด ํจ์๋ ์๋ฒ์์ ์คํ๋จ!
'use server'
export async function addItem(formData) {
const item = formData.get('item')
// DB์ ์ ์ฅํ๋ ์ฝ๋ (๋น๋ฐ ํค๊ฐ ์์ด๋ ์์ ํจ!)
await db.items.create({ data: { name: item } })
// ํ์ด์ง ๋ฐ์ดํฐ ๊ฐฑ์ - ์๋ก๊ณ ์นจ ์์ด!
revalidatePath('/items')
}
// ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์ ์ฐ๋ ๊ฑด ์ ๋ง ์ฌ์
export default function AddItemForm() {
return (
<form action={addItem}>
<input name="item" placeholder="ํ ์ผ ์ถ๊ฐํ๊ธฐ" type="text" />
<button type="submit">์ถ๊ฐ</button>
</form>
)
}
Next.js์ Image ์ปดํฌ๋ํธ๋ ์ผ๋ฐ img ํ๊ทธ๋ณด๋ค ํจ์ฌ ๋ง์ ๊ธฐ๋ฅ์ ์๋์ผ๋ก ์ ๊ณตํด์ค:
import Image from 'next/image'
export default function Page() {
return (
<Image
src="/profile.png"
width={500}
height={500}
alt="์ฌ์ฉ์ ํ๋กํ ์ด๋ฏธ์ง"
// ์ด๋ ๊ฒ๋ง ์จ๋ ์๋์ผ๋ก ์ต์ ํ๊ฐ ์ ์ฉ๋จ!
/>
)
}
์ธ๋ถ ์ฌ์ดํธ์ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ฝ๊ฐ์ ์ค์ ์ด ํ์ํ๋ฐ, ๋ณด์์์ ์ด์ ๋ก ์ด๋ค ์ฌ์ดํธ์ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ ์ง ๋ช ์ํด์ผ ํจ:
// next.config.js์ ์ถ๊ฐํ๊ธฐ
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com', // ์ฌ๊ธฐ์ ์ด๋ฏธ์ง ๊ฐ์ ธ์ฌ ์ฌ์ดํธ ๋๋ฉ์ธ ๋ฃ๊ธฐ
port: '',
pathname: '/account123/**', // ํน์ ๊ฒฝ๋ก๋ง ํ์ฉํ๊ฑฐ๋ '/**'๋ก ๋ชจ๋ ๊ฒฝ๋ก ํ์ฉ
},
],
},
}
์ฒ์์ ๊ท์ฐฎ์ ๋ณด์ด์ง๋ง, ์ด๋ฐ ์ ํ์ด ์์ด์ ์ ์์ ์ธ ์ฌ์ดํธ์ ์ด๋ฏธ์ง๊ฐ ์ฐ๋ฆฌ ์ฑ์ ๋ก๋๋๋ ๊ฑธ ๋ฐฉ์งํ ์ ์์!
Next.js๋ Tailwind CSS์ ์ฐฐ๋ก๊ถํฉ์:
๊ตฌ๊ธ ๊ฒ์๊ฒฐ๊ณผ์ ์์ ๋ฏธ๋์ด ๊ณต์ ์ ํ์๋ ์ ๋ณด๋ฅผ ์ฝ๊ฒ ์ค์ ํ ์ ์์:
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'test', // ํญ์ ํ์๋ ์ ๋ชฉ
description: 'description test', // ๊ฒ์ ๊ฒฐ๊ณผ์ ํ์๋ ์ค๋ช
}
export default function Page() {
return <div>๋ด์ฉ์ ์ฌ๊ธฐ์!</div>
}
import type { Metadata, ResolvingMetadata } from 'next'
type Props = {
params: { id: string }
searchParams: { [key: string]: string | string[] | undefined }
}
export async function generateMetadata(
{ params, searchParams }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
// ์๋ฅผ ๋ค์ด ์ํ ํ์ด์ง๋ผ๋ฉด ์ํ ID๋ก ์ ๋ณด๋ฅผ ๊ฐ์ ธ์์
const id = params.id
const product = await fetch(`https://api.example.com/products/${id}`).then((res) => res.json())
// ํ์ด์ง๋ง๋ค ๋ค๋ฅธ ์ ๋ชฉ๊ณผ ์ด๋ฏธ์ง๋ฅผ ์ค์ ํ ์ ์์!
return {
title: `${product.title}`,
openGraph: {
images: [`/products/${id}.jpg`],
description: product.description,
},
}
}
export default function ProductPage({ params }: Props) {
return <div>์ํ ์ ๋ณด๊ฐ ์ฌ๊ธฐ์ ํ์๋จ</div>
}
์ด ๊ธฐ๋ฅ๋ค ๋๋ถ์ Next.js๋ก ๊ฐ๋ฐํ๋ฉด ์ฑ๋ฅ ์ข๊ณ ์ฌ์ฉ์ ๊ฒฝํ ๋ฐ์ด๋ ์น์ฌ์ดํธ๋ฅผ ์ฝ๊ฒ ๋ง๋ค ์ ์์! ๐