25.07.01 - se5ri/React GitHub Wiki
-
next/link
ํจํค์ง์ ์๋ ์ปดํฌ๋ํธimport Link from "next/link"
-
Next.js์ App ๋ผ์ฐํฐ์ ๋ผ์ฐํ ๊ธฐ๋ฅ์ ๊ตฌํํ ์ปดํฌ๋ํธ
-
a ํ๊ทธ ๋์ ์ฌ์ฉ
- Link ์ปดํฌ๋ํธ๋ ๋ ๋๋ง ๋๋ฉด a ํ๊ทธ๋ก ๋ฐ๋
import Link from "next/link";
...
<li><Link href="/" className={`hover:underline`}>Home</Link></li>
<li><Link href="/about" className={`hover:underline`}>About</Link></li>
<li><Link href="/posts" className={`hover:underline`}>๊ฒ์ํ</Link></li>
<li><Link href="/user/login" className={`hover:underline`}>๋ก๊ทธ์ธ</Link></li>
<li><Link href="/user/signup" className={`hover:underline`}>ํ์๊ฐ์
</Link></li>
...
import Link from "next/link";
...
<li><Link href="/posts" className="block hover:bg-gray-700 p-2 rounded">๋ชฉ๋ก ์กฐํ</Link></li>
<li><Link href="/posts/new" className="block hover:bg-gray-700 p-2 rounded">๊ธ์ฐ๊ธฐ</Link></li>
...
-
usePathname()
ํ ์ ์ด์ฉํด์ url ํ์ธ ํ href์ ๋น๊ต -
app/globals.css ์์ฑ
... /* Tailwind CSS์ ์ปค์คํ ์ปดํฌ๋ํธ ํด๋์ค ์ ์ */ @layer components { .cs-active { @apply text-orange-500; } }
-
app/layout.tsx ์์
'use client'; import './globals.css'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; export default function RootLayout({ children, }: { children: React.ReactNode }) { const pathname = usePathname(); console.log(pathname); const isActive = (path: string) => pathname === path ? 'cs-active' : ''; return ( <html lang="ko"> <body className="flex flex-col h-screen"> <header className="bg-blue-500 text-white p-4"> <nav> <ul className="flex space-x-4"> <li><Link href="/" className={`hover:underline ${isActive('/')}`}>Home</Link></li> <li><Link href="/about" className={`hover:underline ${isActive('/about')}`}>About</Link></li> <li><Link href="/posts" className={`hover:underline ${isActive('/posts')}`}>๊ฒ์ํ</Link></li> <li><Link href="/user/login" className={`hover:underline ${isActive('/user/login')}`}>๋ก๊ทธ์ธ</Link></li> <li><Link href="/user/signup" className={`hover:underline ${isActive('/user/signup')}`}>ํ์๊ฐ์ </Link></li> </ul> </nav> </header> { children } </body> </html> ); }
-
ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์์ผ๋ก ํ์ด์ง ์ด๋ ๊ฐ๋ฅ
-
ํ์ด์ง ์ด๋ ์ SSR, SSG, ๋ฐ์ดํฐ fetching, ์ ํ ํจ๊ณผ ๋ฑ Next.js์ ๊ธฐ๋ฅ์ ํ์ฉํ ์ ์์ผ๋ฏ๋ก ์ง์ window.location์ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค ๊ถ์ฅ๋จ
-
๊ผญ ํ์ํ ๊ฒฝ์ฐ๊ฐ ์๋๋ผ๋ฉด Link ์ปดํฌ๋ํธ ์ฌ์ฉ ๊ถ์ฅ
-
'use client' ์ง์์ด๊ฐ ์๋ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์๋ง ์ฌ์ฉ ๊ฐ๋ฅ
'use client' import { useRouter } from 'next/navigation';
-
router.push(url)
: ์ง์ ํ ๊ฒฝ๋ก๋ก ์ด๋(ํ์ด์ง ์ถ๊ฐ) -
router.replace(url)
: ์ง์ ํ ๊ฒฝ๋ก๋ก ์ด๋(ํ์ด์ง ๊ต์ฒด) -
router.back()
: ์ด์ ํ์ด์ง๋ก ์ด๋ -
router.forward()
: ๋ค์ ํ์ด์ง๋ก ์ด๋ -
router.refresh()
: ํ์ฌ ํ์ด์ง ์๋ก๊ณ ์นจ
-
์๋ฒ์ธก์์ ํ์ด์ง ์ด๋(๋ฆฌ๋๋ ์ ) ์ ์ฌ์ฉํ๋ ํจ์
- ์๋ฒ ์ปดํฌ๋ํธ, ์๋ฒ ํจ์, ๋ผ์ฐํธ ํธ๋ค๋ฌ ๋ฑ์์ ์ฌ์ฉ
-
ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์ ๋ ๋๋ง ์ค์๋ ์ฌ์ฉ ๊ฐ๋ฅํ์ง๋ง, ์ด๋ฒคํธ ํธ๋ค๋ฌ์์๋ ์ฌ์ฉ ๋ถ๊ฐ
- ํด๋ผ์ด์ธํธ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ์์๋ useRouter์ push/replace ์ฌ์ฉ
-
๊ธฐ๋ณธ์ ์ผ๋ก 307 ์ํ ์ฝ๋๋ก ์๋ต
- 307 ์๋ต ์ํ์ฝ๋: Temporary Redirect, ์๋ ์์ฒญ ๋ฐฉ์๊ณผ ๋ณธ๋ฌธ์ผ๋ก ์๋ก์ด ํ์ด์ง ์์ฒญ, ๋ค์๋ฒ ์์ฒญ์๋ ์ด์ URL ์ฌ์ฉ
-
์๋ฒ ํจ์์ผ ๊ฒฝ์ฐ(POST ์์ฒญ์ ์ฑ๊ณต ํ์ด์ง๋ก ์ด๋ํ ๋) 303 ์๋ต ์ํ ์ฝ๋๋ก ์๋ต
- 303 ์๋ต ์ํ์ฝ๋: See Other, ์๋ก์ด ํ์ด์ง๋ก GET ์์ฒญ
import { redirect } from 'next/navigation';
'use server';
import { redirect } from 'next/navigation';
export async function createPost(formData) {
// ๊ฒ์๊ธ ๋ฑ๋ก ๋ก์ง...
redirect('/posts'); // ๋ฑ๋ก ํ ๋ชฉ๋ก์ผ๋ก ์ด๋
}
- ์๋ต ์ํ์ฝ๋๊ฐ 308์ธ ์ ๋ง ๋ค๋ฅด๊ณ redirect์ ๋์ผ
- 308 ์๋ด ์ํ ์ฝ๋: Permanent Redirect, ์๋ ์์ฒญ ๋ฐฉ์๊ณผ ๋ณธ๋ฌธ์ผ๋ก ์๋ก์ด ํ์ด์ง ์์ฒญ, ๋ค์๋ถํฐ๋ ์๋ก์ด URL ์ฌ์ฉ
- ๋ธ๋ผ์ฐ์ ์ history API ์ฌ์ฉ
- window.history.pushState
- window.history.replaceState
- usePathname(), useSearchParams() ํ ์ผ๋ก URL๊ณผ ํ๋ผ๋ฏธํฐ ์ถ์ถํด์ low-level๋ก URL ๋ณ๊ฒฝ ๊ฐ๋ฅ
- useRouter() ํ ์ ์ฌ์ฉํ๋๊ฒ ํ์ด์ง ์ ํ ์ SSR, SSG, ๋ฐ์ดํฐ fetching, ํ์ด์ง ์ ํ ํจ๊ณผ ๋ฑ Next.js ๊ธฐ๋ฅ์ ํ์ฉํ ์ ์์ผ๋ฏ๋ก useRouter() ๊ถ์ฅ
-
์ ์ธ์ redirect
import type { NextConfig } from "next"; const nextConfig: NextConfig = { /* config options here */ async redirects() { return [ { source: '/home', destination: '/', permanent: true, }, { source: '/community/:slug', destination: '/posts/:slug', permanent: true, }, ] }, }; export default nextConfig;
-
๋ฏธ๋ค์จ์ด์์ ์ฌ์ฉ
-
์ฌ์ฉ์ฌ๋ก: ๋ก๊ทธ์ธ๋์ง ์์ ์ฌ์ฉ์๋ฅผ ๋ก๊ทธ์ธ ํ์ด์ง๋ก ์ด๋
import { NextResponse } from 'next/server'; import { authenticate } from 'auth-provider'; export function middleware(request) { const isAuthenticated = authenticate(request); // ์ธ์ฆ๋ ์ฌ์ฉ์๋ผ๋ฉด ์๋์ ์์ฒญ์์ ์งํ if (isAuthenticated) { return NextResponse.next(); } // ์ธ์ฆ๋์ง ์์ ์ฌ์ฉ์๋ผ๋ฉด ๋ก๊ทธ์ธ ํ์ด์ง๋ก ์ด๋ return NextResponse.redirect(new URL('/login', request.url)); } export const config = { matcher: '/posts/new', }
- ๊ณ ์ ๋ URL์ด ์๋ ๋ฐ๋์ ์๋ ๋ถ๋ถ์ ๋ํด์ ๋ผ์ฐํ
์ ์ ์ํ ๋ ํด๋๋ช
์ ๋๊ดํธ๋ก ๋ฌถ์ด์ ์์ฑ
- posts/1, posts/2 -> posts/[id]
- ์ค์ ์์ฒญํ URL์ ๋์ ๋ผ์ฐํธ ๊ฐ์ layout, page, route, generateMetadata ํจ์์ params prop์ผ๋ก ์ ๋ฌ๋จ
-
app/posts/1 -> app/posts/[id]๋ก ์์
-
app/posts/[id]/page.tsx์ ์ถ๊ฐ
export default async function InfoPage({ params }: { params: { id: string } }) { const { id } = await params; // Next.js 15 ๋ถํฐ params๋ ๋น๋๊ธฐ ์ฒ๋ฆฌ ํ์ await new Promise(resolve => setTimeout(resolve, 1000*2)); return ( <h1>์์ธ ์กฐํ - { id }๋ฒ ๊ฒ์๋ฌผ</h1> ); }
-
app/posts/[id]/page.tsx ํ์ผ์ด ์์๋ ๋งค์นญ๋๋ URL๊ณผ params ๊ฐ
- /posts/1 -> { id: '1' }
- /posts/2 -> { id: '2' }
- /posts/3 -> { id: '3' }
- ...
-
๋์ ๋ผ์ฐํธ๋ฅผ ์ฌ์ฉํด์ ํน์ ๊ฒ์๊ธ์ ๋ฌ๋ฆฐ ์ข์์ ๋ชฉ๋ก, ๊ด์ฌ๊ธ๋ก ๋ฑ๋กํ ๋ชฉ๋ก๊ณผ ์ข์์ ์์ธ์ ๋ณด, ๊ด์ฌ๊ธ ์์ธ ์ ๋ณด๋ฅผ ๋ณด์ฌ์ค ๋ ๋ง๋ค์ด์ผ ํ ํ์ผ
- app/posts/[id]/[slug]/page.tsx
- /posts/1/likes -> { id: '1', slug: 'likes' }
- /posts/2/likes -> { id: '2', slug: 'likes' }
- /posts/2/favorites -> { id: '2', slug: 'favorites' }
- app/posts/[id]/[slug]/[sid]/page.tsx
- /posts/3/likes/4 -> { id: '3', slug: 'likes', sid: '4' }
- /posts/3/favorites/4 -> { id: '3', slug: 'favorites', sid: '4' }
- app/posts/[id]/[slug]/page.tsx
-
๋๊ดํธ ์์ ์ค์ํ
...
๋ฅผ ์ถ๊ฐํ๋ฉด ํ์ ๊ฒฝ๋ก๊ฐ ๋ ์์ด๋ ๋งค์นญ๋จ -
๋งค์นญ๋ ๊ฐ์ ์ ์ฒด ํ์ ๊ฒฝ๋ก๋ฅผ ํฌํจํด์ params์ ๋ฐฐ์ด๋ก ์ ์ฅ๋จ
-
Catch-all ์ธ๊ทธ๋จผํธ๋ฅผ ์ด์ฉํด์ ํน์ ๊ฒ์๊ธ์ ๋ฌ๋ฆฐ ์ข์์ ๋ชฉ๋ก, ๊ด์ฌ๊ธ๋ก ๋ฑ๋กํ ๋ชฉ๋ก๊ณผ ์ข์์ ์์ธ์ ๋ณด, ๊ด์ฌ๊ธ ์์ธ ์ ๋ณด๋ฅผ ๋ณด์ฌ์ค ๋ ๋ง๋ค์ด์ผ ํ ํ์ผ๊ณผ params ๊ฐ
- app/posts/[id]/[...slug]/page.tsx
- /posts/1 -> ๋งค์นญ๋์ง ์์
- /posts/1/likes -> { id: '1', slug: ['likes'] }
- /posts/2/likes -> { id: '2', slug: ['likes'] }
- /posts/2/favorites -> { id: '2', slug: ['favorites']}
- /posts/3/like/4 -> { id: '3', slug: ['likes', '4'] }
- /posts/3/favorites/4 -> { id: 3', slug: ['favorites', '4'] }
- app/posts/[id]/[...slug]/page.tsx
-
ํด๋๋ช ์ ์ด์ค ๋๊ดํธ๋ก ๋ฌถ์ด์ ์์ฑํ๋ฉด Catch-all ์ธ๊ทธ๋จผํธ๋ฅผ ์ ํ์ฌํญ์ผ๋ก ์ง์
-
ํน์ ๊ฒ์๊ธ๊ณผ ๋๊ธ ๋ชฉ๋ก, ๋๊ธ ์์ธ ์ ๋ณด๋ฅผ ํ๋์ page๋ก ์ฒ๋ฆฌํ ๊ฒฝ์ฐ params ๊ฐ
- app/posts/[id]/...slug/page.tsx
- /posts/1 -> { id: '1' }
- /posts/2 -> { id: '2' }
- /posts/3/replies -> { id: '3', slug: ['replies'] }
- /posts/3/replies/2 -> { id: '3', slug: ['replies', '2'] }
- app/posts/[id]/...slug/page.tsx
-
๋์ ๋ผ์ฐํธ๋ก ๊ตฌ์ฑ๋ ํ์ด์ง์ params๋ฅผ ๋ฏธ๋ฆฌ ์ง์ ํด์ ๋น๋์ ํด๋น ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฐ์ง๋ ํ์ด์ง๋ฅผ ์ ์ ์ผ๋ก ์์ฑ(SSG)
-
๋ฏธ๋ฆฌ ์์ฑํ ์ ์ ํ์ด์ง์ params๋ฅผ ๋ฐฐ์ด๋ก ๋ฐํํ๋๋ก ์์ฑ
// ์ด ํจ์๊ฐ ๋ฐํํ ๋ฐฐ์ด๋งํผ SSG ํ์ด์ง๋ฅผ ๋ฏธ๋ฆฌ ์์ฑ // ๋น๋ํ๋ฉด .next/server/app/posts/1.html, 2.html, 3.html export function generateStaticParams() { // ๊ณต์ง๊ธ์ ๋ํ fetch ์์ const posts = [ { id: '1', title: '1๋ฒ ์ ๋ชฉ' }, { id: '2', slug: '2', sid: '3', title: '2๋ฒ ์ ๋ชฉ' }, { id: '3', slug: '2', sid: '3', title: '4๋ฒ ์ ๋ชฉ' }, ]; return posts; } export default async function Page({ params: { id } }){ const resJson = await fetchPost(id); let data = resJson.ok ? resJson.item : null; return ( ... ); }
-
๋น๋ ํ ๋ ๋์ ์์
- ๋น๋์ generateStaticParams() ํจ์ ํธ์ถ ํ ๋ฐํ ๋ฐ์ ๋ฐฐ์ด์ ๊ฐ ์์๋ฅผ params๋ก ๊ตฌ์ฑํด์ Page ์ปดํฌ๋ํธ ํธ์ถ
- Page ์ปดํฌ๋ํธ์์ ๋ฐํ ๋ฐ์ HTML์ ๋น๋ ๊ฒฐ๊ณผ๋ก ์ ์ฅ(posts/1.html, 2.html, 3.html)
- ์ดํ ๋ธ๋ผ์ฐ์ ์ posts/1 ์์ฒญ์ด ์ค๋ฉด ๋น๋์ ๋ง๋ค์ด๋ ์ ์ ๋ผ์ฐํ ํ ์ด๋ธ์์ ๋งค์นญ๋๋ url์ด ์๋์ง ํ์ธ ํ posts/[id]/page.tsx ํ์ผ์ ์คํํ์ง ์๊ณ posts/1.html์ ์๋ต
- ๋ธ๋ผ์ฐ์ ๊ฐ posts/4 ์์ฒญ์ ๋ณด๋ด๋ ๊ฒฝ์ฐ ์ ์ ๋ผ์ฐํ ํ ์ด๋ธ์ ๋งค์นญ๋๋ url์ด ์์ผ๋ฏ๋ก posts/[id]/page.tsx ํ์ผ์ ์คํํ์ฌ ์๋ต
-
app ๋ผ์ฐํฐ๋ app ํ์ ํด๋๊ฐ URL ๊ฒฝ๋ก์ ๋งคํ๋จ
-
ํด๋๊ฐ URL ๊ฒฝ๋ก์ ํฌํจ๋์ง ์๊ฒ ํ๊ณ ์ถ์๋ ๋ผ์ฐํธ ๊ทธ๋ฃน์ ์์ฑ
-
(ํด๋๋ช )
์ฒ๋ผ ํด๋๋ช ์()
๋ฅผ ๋ถ์ฌ์ ์์ฑ -
URL์ ์ํฅ์ ์ฃผ์ง ์๊ณ ์ฌ๋ฌ ํ์ด์ง๋ฅผ ํ๋์ ํด๋์ ๋ฌถ์ด์ ๊ด๋ฆฌ
-
๋ค๋ฅธ ๋ผ์ฐํธ ๊ทธ๋ฃน์ ๋์ผํ ํ์ ๊ฒฝ๋ก ์์ฑ์ ์ปดํ์ผ ์๋ฌ ๋ฐ์
project-root/ โโโ app/ โ โโโ(user)/ โ โ โโโ login/ โ โ โ โโโ page.tsx โ โ โโโ signup/ โ โ โ โโโ page.tsx
-
login, signup ํด๋๋ฅผ user ํด๋ ํ์๋ก ๊ทธ๋ฃนํ ํด์ ๊ด๋ฆฌํ๋ ๊ฒฝ์ฐ ๊ฒฝ๋ก์ user๊ฐ ํฌํจ๋จ
project-root/ โโโ app/ โ โโโ user/ โ โ โโโ login/ โ โ โ โโโ page.tsx โ โ โโโ signup/ โ โ โ โโโ page.tsx
- /user/login -> app/user/login/page.tsx
- /user/signup -> app/user/signup/page.tsx
-
๊ฒฝ๋ก์์ user๋ฅผ ์ ๊ฑฐํ๊ธฐ ์ํด์ user ํด๋๋ฅผ ์ ๊ฑฐ
project-root/ โโโ app/ โ โโโ login/ โ โ โโโ page.tsx โ โโโ signup/ โ โ โโโ page.tsx
- /login -> app/login/page.tsx
- /signup -> app/signup/page.tsx
-
๋ผ์ฐํธ ๊ทธ๋ฃน์ผ๋ก ๊ด๋ฆฌ
project-root/ โโโ app/ โ โโโ(user)/ โ โ โโโ login/ โ โ โ โโโ page.tsx โ โ โโโ signup/ โ โ โ โโโ page.tsx
- /login -> app/(user)/login/page.tsx
- /signup -> app/(user)/signup/page.tsx
- ๋์ผํ URL depth์ ์๋ ํ์ด์ง์ ๋ค๋ฅธ layout์ ์ ์ฉํ๊ณ ์ถ์ ๋๋ ๋ผ์ฐํธ ๊ทธ๋ฃน์ ๊ฐ๊ฐ ๋ง๋ค๊ณ layout ์์ฑ
account, cart, checkout ํ์ด์ง์์ account, cart์๋ง ๋์ผํ layout์ ์ ์ฉํ๊ณ ์ถ์ ๋
- _๋ก ์์ํ๋ ํด๋๋ page ํ์ผ์ด ์์ด๋ ๋ผ์ฐํ ์์ ์ ์ธ
- ํ์ฉ ์ฌ๋ก
- UI ๋ก์ง๊ณผ ๋ผ์ฐํ ๋ก์ง ๋ถ๋ฆฌ
- ํ๋ก์ ํธ ๋ฐ Next.js ์ํ๊ณ ์ ๋ฐ์ ๊ฑธ์ณ ๋ด๋ถ ํ์ผ์ ์ผ๊ด๋๊ฒ ๊ตฌ์ฑ
- ์ฝ๋ ํธ์ง๊ธฐ์์ ํ์ผ ๋ถ๋ฅ ๋ฐ ๊ทธ๋ฃนํ
- ์๋ฒ ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฒฝ๋ก๋ณ๋ก ์ฝ๋๋ฅผ ์์ ๋ฒ๋ค๋ก ๋ถํ ํด์ ๋ธ๋ผ์ฐ์ ๊ฐ ๋ค์ด๋ก๋ํ๊ณ ์คํํ ์ ์์ผ๋ฏ๋ก ๋ฐ์ดํฐ์ ์๊ณผ ์๋ต์๊ฐ์ด ์ค์ด๋ค์ด ์ฑ๋ฅ ํฅ์
- ๋น๋ ํ
.next/server/app
ํด๋์์ ํ์ธ
-
<Link>
์ปดํฌ๋ํธ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ๋งํฌ๋ฅผ ๋๋ฅด๊ธฐ ์ ์ ํ์ด์ง๋ฅผ ๋ฏธ๋ฆฌ ๋ก๋ํ๋ ์์ - ํ๋ก๋์ ํ๊ฒฝ์์๋ง ํ์ฑํ ๋จ
-
false: prefetch ๋์ ์ํจ
-
null(๊ธฐ๋ณธ๊ฐ)
- ์ ์ ๋ผ์ฐํธ์ผ ๊ฒฝ์ฐ ๋งํฌ๊ฐ ํ๋ฉด์ ๋ณด์ผ ๋(๋ทฐํฌํธ์ ๋ค์ด์ฌ ๋) ์ ์ฒด ํ์ด์ง๊ฐ ํ๋ฆฌํจ์น๋์ด ์บ์๋จ
- ๋์ ๋ผ์ฐํธ์ผ ๊ฒฝ์ฐ ๋งํฌ๊ฐ ํ๋ฉด์ ๋ณด์ผ ๋ ๋ ๋๋ง๋ ์ปดํฌ๋ํธ ํธ๋ฆฌ์์ ์ฒซ๋ฒ์งธ loading.tsx ํ์ผ์ด ๋ํ๋ ๋๊น์ง๋ง ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ์ ธ์ด(30์ด ๋์ ์บ์๋จ)
- ์ค์ ํ์ด์ง๋ฅผ ์์ฒญํ ๋(ํด๋ฆญ ํ ๋) ๋ก๋ฉ ์ํ๋ฅผ ์ฆ์ ๋ณด์ฌ ์ฃผ๊ณ ์ดํ์ ๋ด์ฉ์ ๊ฐ์ ธ์ด
-
true
- ๋งํฌ๊ฐ ํ๋ฉด์ ๋ณด์ด์ง ์์๋(DOM์ ์กด์ฌํ๊ธฐ๋ง ํ๋ฉด) ์ ์ ๋ผ์ฐํธ์ ๋์ ๋ผ์ฐํธ ๋ชจ๋ ๋ค ์ ์ฒด ํ์ด์ง๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ์ ธ์ด(5๋ถ ๋์ ์บ์๋จ)
-
ํ๋ฆฌํจ์นญ๋ ๋ฐ์ดํฐ์ ๋ ์ด์์์ 30์ด ๋์ ๋ผ์ฐํฐ ์บ์์ ์ ์ฅ๋จ
- ๋ผ์ฐํฐ ์บ์๋ ๋นํ์ฑํ ์ํฌ ์ ์์
- router.refresh() ํธ์ถ ์ ๋ผ์ฐํฐ ์บ์ ์ญ์
- ํ์ด์ง ์ด๋์ ๊ณต์ ๋ ์ด์์์ ์ ์งํ ์ฑ๋ก ๋ณ๊ฒฝ๋ ํ์ด์ง๋ง ๋ ๋๋ง
- /posts/3 -> /posts/2๋ก ์ด๋์ app/layout.tsx, app/posts/layout.tsx๋ ๋ค์ ๋ ๋๋ง ํ์ง ์์
- ์คํฌ๋กค์ ์ ์งํ๊ณ ๋ผ์ฐํฐ ์บ์๋ฅผ ์ฌ์ฌ์ฉ
- ๋ผ์ฐํ ํด๋ ๋ด์ page, route ํ์ผ์ด ์๋ ๊ฒฝ์ฐ์๋ง ๋ผ์ฐํ ๋จ
- page์ route ํ์ผ๋ง ๋ผ์ฐํ ๋จ
- ํ๋ก์ ํธ ํ์ผ๊ณผ ํด๋๋ฅผ ์ด๋ป๊ฒ ๊ตฌ์ฑํ ๊ฒ์ธ์ง์ ๋ํด์ ์ฌ๋ฐ๋ฅด๊ฑฐ๋ ํ๋ฆฐ ๋ฐฉ๋ฒ์ ์์
- ์ฌ๋ฌ ์ ๋ต ์ค ํ์๊ฒ ์ ํฉํ ๋ฐฉ์์ ์ ํํ๊ณ ์ผ๊ด์ฑ์ ์ ์งํด์ผ ํจ
- app ํด๋๋ ๋ผ์ฐํ ์ผ๋ก๋ง ์ฌ์ฉํ๊ณ ๋๋จธ์ง ์ฝ๋๋ app ํด๋ ์ธ๋ถ์ ์ ์ฅ
- ๋ชจ๋ ์ฝ๋๋ฅผ app ํด๋ ๋ด๋ถ์ ์ ์ฅ
- ๊ณต์ฉ ์ปดํฌ๋ํธ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ app ํด๋ ํ์์ ์์ฑํ๊ณ ๊ฐ ํ์ด์ง๋ณ๋ก ์ฌ์ฉํ ์ปดํฌ๋ํธ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๊ฐ ํ์ด์ง ํด๋ ํ์์ ์์ฑ
๐ ch10 02
- ๐ป 02