(1) ์ค์นํ๊ธฐ
npx create-next-app@latest
or
yarn create next-app

ํน๋ณํ ๊ฒ์ด ์๋ค๋ฉด ์์ ๊ฐ์ด ์ธํ
ํ๊ธฐ
(2) ๊ธฐ๋ณธ ํ์ผ
Next.js์์๋ layout.tsx, page.tsx์ด ๋ ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ฅ ๋ง์ด ๋ค๋ฃจ๊ฒ ๋ ๊ฒ์

page.tsx
์ ๋ํ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ์
tailwind.config.ts / package.json ๋ฑ ์ฌ๋ฌ ํ์ผ์ด ์ธํ ๋ผ์์
build ํ start๋ฅผ ํด์ค์ผ ํจ
yarn build -> yarn start
src > app > page.tsx ํ์ผ์ด UI๋ฅผ ํธ๋ค๋งํ๋ ์ฃผ ํ์ผ์ด๋ค
(1) Tree ๊ด๋ จ

Tree
Subtree
Root
Leaf

(1) page.tsx
์ด๋ฏธ ๋ค๋ค๋ดค๋ ๋๋ก page.tsx๋ main ui๊ฐ ํ์๋ ๊ณณ์.
๋ฐ์์๋ ๋ค๋ฃจ๊ฒ ์ง๋ง, ํด๋๋ฅผ ๋ง๋ค์ด๊ฐ๋ฉด์ ์ฐ๋ฆฌ๋ routing์ด ์๋ ๊ตฌํ๋๋ ๊ฒ์ ๋ณด๊ฒ ๋ ๊ฒ.
์ด ๊ณผ์ ์์ ํด๋น ํด๋์ page.tsx ํ์ผ์ด ์ฝํ์ง๊ฒ ๋จ
(2) static routing
React์์ Routing์ ๊ตฌํํ๊ธฐ ์ํด ์ฐ๋ฆฌ๋ react-router-dom ํจํค์ง๋ฅผ ์ค์นํ๊ณ ์ธํ
ํ์.
๊ทธ๋ฌ๋ next.jsx์์๋ ๊ทธ๋ ๊ฒ ํ ํ์๊ฐ ์์
src > app ํด๋ ๋ฐ์ test ํด๋๋ฅผ ์๋ก ๋ง๋ค๊ณ ๊ทธ ์์ page.tsx ํ์ผ์ ๋ง๋ค์ด ์ค
// src>app>test>page.tsx
import React from "react";
const TestPage = () => {
return (
<div>
<h1>Test Page</h1>
<p>์๋
ํ์ธ์! ํ
์คํธ ํ์ด์ง์
๋๋ค</p>
</div>
);
};
export default TestPage;
๋ธ๋ผ์ฐ์ ์์ ์ ๊ทผํ๋ฉด?

์๋์ผ๋ก Routing์ด ๋จ.
(3) dynimic routing
React์์ <Route path="/products/:id" element={<Product />} />
์ด๋ฐ ์์ผ๋ก ํ์ง๋ง Next.js์์๋ ํด๋ ์ผ๋ฏ์ ๋๊ดํธ๋ก ๊ฐ์ธ๋ฉด ๋จ. ์ด๋ ๊ฒ ํ๋ฉด ํจํด์ ์ผ์นํ๋ ๋ชจ๋ ๊ฒฝ๋ก๋ฅผ ํ์ด์ง๋ก ์ฐ๊ฒฐํ๊ฒ ๋จ
์๋ฅผ ๋ค์ด app/posts/[id]/page.tsx ํ์ผ์ ๊ฒฝ์ฐ
/posts1, /posts/2 ๋ฑ ๊ฒฝ๋ก์ ๋ํด ๋์ ์ผ๋ก ํ์ด์ง ์์ฑ

Next.js ๊ณต์ ๋ฌธ์์์๋ ์ด๋ ๊ฒ ํํํ๊ณ ์์
๊ฐ ํด๋๋ URL segment์ ๋์๋๋ route์. ์ค์ฒฉ ๋ผ์ฐํ ์ ์ํด์๋ ํด๋๋ก ๊ฐ์ธ์ฃผ๋ฉด ๋จ
์ง์ ์์ฑ์ ํด๋ณธ ์ฝ๋๋ ์ด๋ฌํ๋ค
// app>test>[id]>page.tsx
import React from "react";
const TestDetailPage = ({
params,
}: {
params: {
id: string;
};
}) => {
return <div>Detail ํ์ด์ง : {params.id}</div>;
};
export default TestDetailPage;
์ ์๋ํ๋ ๊ฒ์ ํ์ธํ ์ ์์

(4) route groups
ํด๋๋ง ๋ง๋ค๋ฉด routing์ ํฌํจ์ด ๋๋๋ฐ, ๊ทธ๋ฌ๊ณ ์ถ์ง ์์ ๋๋ ๊ฐ๋จํ๊ฒ ๋ค์๊ณผ ๊ฐ์ด ์ฒ๋ฆฌํ ์ ์์

์ง์ ํด๋ณธ ๊ฒฐ๊ณผ

์ ๋์ด

Next.jsx์์๋ Routing์ ํด๋ ๊ธฐ๋ฐ(Nested Folders)๋ก ๊ตฌํ์ ํ๊ณ ์์. ์ด ๊ณผ์ ์์ ๋ผ์ฐํธ์ ๋ํ ํน์ ์ฒ๋ฆฌ๋ฅผ ์ํด ์์ฑ๋๋ ์ฌ๋ฌ
special files๊ฐ ์๋ค.์๋ฅผ ๋ค์ด ํน์ ๊ฒฝ๋ก ํ์์ ์๋ routing์ ๋ชจ๋ ๊ณตํต layout์ ์ ์ฉํ๊ณ ์ถ๋ค๋์ง, ํน์ ์ปดํฌ๋ํธ๊ฐ ๋ก๋ฉ ์ค์ผ ๋, ์ค๋ฅ๊ฐ ๋ฐ์ํ์ ๋ ๋ณด์ฌ์ฃผ๊ณ ์ถ์ UI๊ฐ ์๋ค๋์ง ๋ฑ
(1) layout
layout ํ์ผ์ ์ด๋ค segment์ ๊ทธ์ ์์ node์ ์๋ ์์๋ค์ด ๊ณตํต์ ์ผ๋ก ์ ์ฉ๋ฐ๊ฒ ํ UI๋ฅผ ์ ์ํจ.
์์ node์ ์๋ ์์๋ค์ด ๊ณตํต ์ ์ฉ์ ๋ฐ์์ผ ํ๊ธฐ ๋๋ฌธ์ ๋ฐ๋์ children prop์ด ์กด์ฌํด์ผ ํจ
๋์ผ layout ์์์ ๋ค๋ฅธ ๊ฒฝ๋ก๋ฅผ ๊ณ์ํด์ ์๋ค๊ฐ๋ค ํ ๋ ๋ฆฌ๋ ๋๋ง์ด ์ผ์ด๋์ง ์๋๋ค. ๋ฐ๋ผ์ headers, footers, sidebars ์ฒ๋ผ ์ ์ ๊ฐ ๊ฒฝ๋ก๋ฅผ ๋ง์๊ป ํ์ํ๊ณ ๋ค๋
๋ ๊ตณ์ด ๋ฐ๋ ํ์๊ฐ ์๋ ๊ฒฝ์ฐ์ ์ ์ฉํจ โฌ
๏ธ ์ดํ ๋ฐฐ์ธ template๊ณผ์ ์ฃผ์ ์ฐจ์ด
โ Next.js๋ฅผ ์ฌ์ฉํ ๋ ์ด๋ ๊ฒ ํ๋ฉด ๋จ
ํน์ segment ์ดํ์ route์์ ์ ์ฉ๋ฐ์ layout UI๋ฅผ ํด๋น ํด๋ ์์ ๋ง๋ฌ

children์ ํฌํจ์์ผ์ ๊ณตํต UI๋ฅผ ๋ง๋ฌ
export default function DashboardLayout({
children, // will be a page or nested layout
}: {
children: React.ReactNode
}) {
return (
<section>
{/* Include shared UI here e.g. a header or sidebar */}
<nav></nav>
{children}
</section>
)
}
์ฐ๋ฆฐ ๋ง๋ ์ ์ด ์์ง๋ง, Next.js ํ๋ก์ ํธ๋ฅผ ์์ฑํ๊ณ ๋๋ฉด ์ด๋ฏธ root ๊ฒฝ๋ก์ layout.tsx ํ์ผ์ด ์กด์ฌํจ

ํด๋น ์ฝ๋์์ 8๋ฒ์งธ ์ค title์ ๋ด์ฉ์ ๋ฐ๊พธ๋ฉด ์ฌ์ดํธ ์ ๋ชฉ์ด ๋ฐ๋
๊ทธ๋ฆฌ๊ณ ํด๋น return ๋ฌธ์์ ์คํ์ผ์ ์ ์ฉํ๋ฉด ๋ชจ๋ ์ปดํฌ๋ํธ๊ฐ ์ํฅ์ ๋ฐ์
(2) template
template ํ์ผ์ layout๊ณผ ์ ์ฌํ ์ปดํฌ๋ํธ์.
๊ทธ๋์ ์ด ๋ ์์๋ ๋ ๋น๊ต๋์์ด ๋จ.
๊ฐ์ฅ ๋๋๋ฌ์ง๋ ์ฐจ์ด๋
์ํ๋ฅผ ์ ์งํ๋๊ฐ? ๋ฆฌ๋ ๋๋ง์ด ์ผ์ด๋๋๊ฐ?
๊ฒฝ๋ก ์ ๋ฐ์ ๊ฑธ์ณ์ ์ํ๊ฐ ์ ์ง๋๋ layout๊ณผ ๋ฌ๋ฆฌ template์ ๋ผ์ฐํ ์ ํ์ํ ๋ ๊ฐ ํ์ ํญ๋ชฉ์ ๋ํด ์ ์ธ์คํด์ค๋ฅผ ๋ง๋ฌ. ์ฆ, ์ ์ ์ ์ฅ์์ ๋์ผํ Template์ ๊ณต์ ํ๋ ๊ฒฝ๋ก ์ฌ์ด๋ฅผ ์๋ค๊ฐ๋ค ํ ๋ DOM ์์๊ฐ ๋ค์ ์์ฑ๋๋ค๋ ๊ฒ์ ์๋ฏธํจ
(2)-1. use-case
๊ฒฐ๋ก : ํน์ ํ ์ด์ ๊ฐ ์์ง ์๋ ํ, layout์ ์ฌ์ฉํ์
(3) not-found
next.js์์๋ ์ฐ๋ฆฌ์๊ฒ ์ต์ํ 404 not found ํ์ด์ง๋ฅผ ๋ณ๋ ์ค์ ํ์ง ์์๋ ๊ธฐ๋ณธ ์คํ์ผ์ด ๋ not found ํ์ด์ง ์ ๊ณต, ๊ทธ๋ฌ๋ ๋ง์ ๋ค์ง ์์ผ๋ฉด ์ง์ ๋ง๋ค ์ ์์
// src>app>not-found.tsx
import React from "react";
const NotFound = () => {
return <div>์กด์ฌํ์ง ์๋ ํ์ด์ง์
๋๋ค.</div>;
};
export default NotFound;
(4) metadata์ SEO
Next.js๋ ๊ธฐ๋ณธ์ ์ผ๋ก MetaData๋ฅผ ๊ฐ๊ณ ์์

Next.js๋ ํฅ์๋ SEO๋ฅผ ์ ๊ณตํ๊ธฐ ์ํด ๋ง์ ์ ๋ณด๋ฅผ metadata ๊ฐ์ฒด ํํ๋ก ์ง์ํ๊ณ ์์
react์์๋ vite๋ฅผ ์ฐ๋ CRA๋ฅผ ์ฐ๋ index.html ํ์ผ์ด ์กด์ฌํ๊ณ , ์ด ํ์ผ์ head ํ๊ทธ์ ์ฐ๋ฆฌ๊ฐ SEO ํฅ์์ ์ํด ์ฌ๋ฌ meta, link ํ๊ทธ ๋ฑ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์์ฑํ์
(4)-1. SEO์ ๋ํด ์์ธํ๊ฒ ์์๋ณด๊ธฐ
SEO(Search Engine Optimization, ๊ฒ์ ์์ง ์ต์ ํ)๋ ์น์ฌ์ดํธ๋ ์นํ์ด์ง๋ฅผ ๊ฒ์ ์์ง์์ ๋ ๋์ ์์์ ๋ ธ์ถ์ํค๊ธฐ ์ํ ๋ฐฉ๋ฒ์. ๊ฐ๋จํ๊ฒ ๋งํด์, SEO๋ ๊ฒ์ ๊ฒฐ๊ณผ์์ ์น์ฌ์ดํธ๊ฐ ๋ ์์ ๋ํ๋๋๋ก ๋ง๋๋ ์ฌ๋ฌ ๊ธฐ์ ๊ณผ ์ ๋ต
์๋ฅผ ๋ค์ด img ํ๊ทธ ๋ด์ 'alt' ์์ฑ์ ์๋นํ ์ค์
<img src="../assets/sample.jpg" /> <img src="../assets/sample.jpg" alt="sample image" />
- ๊ฒ์ ์์ง์ ์ด๋ฏธ์ง ๋ด์ฉ ์ค๋ช ํ๊ธฐ:
altํ ์คํธ๋ ๊ฒ์ ์์ง์ ์ด๋ฏธ์ง์ ๋ด์ฉ๊ณผ ๋งฅ๋ฝ์ ์ค๋ช ํด ์ค. ํ ์คํธ๋ฅผ ํตํด ์ด๋ฏธ์ง๊ฐ ๋ฌด์์ ๊ดํ ๊ฒ์ธ์ง ์ดํดํ๊ณ , ๊ด๋ จ ๊ฒ์ ์ฟผ๋ฆฌ์ ๋ํ ๊ฒฐ๊ณผ๋ก ํด๋น ์ด๋ฏธ์ง๋ฅผ ๋ ์ ํํ๊ฒ ๋ญํนํ ์ ์์
- ์ ๊ทผ์ฑ ํฅ์:
altํ ์คํธ๋ ์๊ฐ ์ฅ์ ๊ฐ ์๋ ์ฌ์ฉ์๊ฐ ์น์ฌ์ดํธ์ ์ด๋ฏธ์ง ์ฝํ ์ธ ๋ฅผ ์ดํดํ๋ ๋ฐ ๋์์ ์ค. ์ด๋ฌํ ์ ๊ทผ์ฑ ๊ฐ์ ์ ๊ฒ์ ์์ง์ ์ํด ๊ธ์ ์ ์ธ ์ ํธ๋ก ํด์๋์ด ์ ๋ฐ์ ์ธ ์ฌ์ดํธ์ SEO ์ ์๋ฅผ ํฅ์์ํฌ ์ ์์
Next.js์์๋ Config-based MetaData๋ฅผ ํ์ฉํ ์ ์์
export const metadata: Metadata = {
title: "Sparta Next App",
description: "This is awesome Website",
} ๋ฅผ ์ฝ์
ํด๋๊ธฐ๋ง ํ๋ฉด ์ ์ฉ์ด ๋จdynamic
dynamic route๋ฅผ ๊ฐ๊ณ ์๋ route์์ ๋์ ์ผ๋ก ๋ณ๊ฒฝ๋๋ params๋ฅผ ๊ธฐ๋ฐ์ผ๋ก metadata๋ฅผ ๋ณ๊ฒฝํ๊ณ ์ถ์ ๋ generateMetadata function์ ์ฌ์ฉ
import React from "react";
type Props = {
params: {
id: string;
};
};
export function generateMetadata({ params }: Props) {
return {
title: `Detail ํ์ด์ง : ${params.id}`,
description: `Detail ํ์ด์ง : ${params.id}`,
};
}
const TestDetailPage = ({ params }: Props) => {
return <div>Detail ํ์ด์ง : {params.id}</div>;
};
export default TestDetailPage;
(1) Link
Next.js๋
<Link>๋ผ๋ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ๋ฅผ ์ ๊ณต.<Link>ํ๊ทธ๋ ๊ธฐ๋ณธ HTML์ aํ๊ทธ๋ฅผ ํ์ฅํ ๊ฐ๋
1. Link ํ๊ทธ๋ prefetching์ ์ง์
>Link> ์ปดํฌ๋ํธ๋ ๋ทฐํฌํธ์ ๋งํฌ๊ฐ ๋ํ๋๋ ์๊ฐ ํด๋น ํ์ด์ง์ ์ฝ๋์ ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ์ ธ์ค๋ ํ๋ฆฌํ์นญ ๊ธฐ๋ฅ์ ์ง์ํจ. ์ฌ์ฉ์๊ฐ ๋งํฌ๋ฅผ ํด๋ฆญํ์ ๋ ๊ฑฐ์ ์ฆ์ ํ์ด์ง๋ฅผ ๋ณผ ์ ์์2. Link ํ๊ทธ๋ Route ์ฌ์ด์ client-side navigation์ ์ง์
<Link> ์ปดํฌ๋ํธ๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ํ์ด์ง๋ฅผ ๋ก๋ํ๊ธฐ ์ํด ์๋ฒ์ ์์ฒญ์ ๋ณด๋ด๋ ๋์ , ํด๋ผ์ด์ธํธ ์ธก์์ ํ์ด์ง๋ฅผ ๋ฐ๊ฟ์ฃผ๊ธฐ ๋๋ฌธ์ ํ์ด์ง ์ ํ ์ ๋งค์ฐ ๋น ๋ฅธ ์ฌ์ฉ์ ๊ฒฝํ(UX)๋ฅผ ์ ๊ณต(2) useRouter
1. aํ๊ทธ vs Link vs Router
aํ๊ทธ
Linkํ๊ทธ
Router(useRouter)
useRouter๋ฅผ ์ฌ์ฉํ ๋ ํญ์ ์ฝ๋ ์ต์๋จ์
"use client"๋ฅผ ์ฝ์ ํด์ผ ํจ
2. router.push (replace, back, reload)
history stack์ ์์์ผ ํจ. ์ค์ ๋ก history stack์ ํ ๊ฐ๋ผ๊ณ ์ดํดํด์ผ ํจ
- history stack์ ๋ฐฉ๋ฌธ์์ ํ์ด์ง ๋ฐฉ๋ฌธ ์์๋ฅผ ๊ธฐ๋กํ๋ ์์คํ
- ํ์ด์ง ์ด๋ โก๏ธ URL์ด history stack์ ์ถ๊ฐ
- EX: ๋ค๋ก ๊ฐ๊ธฐ, ์์ผ๋ก ๊ฐ๊ธฐ ํ์ ๋ ์ด๋ํ ์ ์๋ ์ด์
router.push
router.replace
router.back
router.reload