7/2 TIL (Next.js)

Hwiยท2024๋…„ 7์›” 2์ผ

TIL

๋ชฉ๋ก ๋ณด๊ธฐ
61/96

๐Ÿ“š ์ง„ํ–‰ํ•œ ๊ณต๋ถ€

  • Routing

๐Ÿ“š Routing

๐Ÿ“– 01. ์ฒซ installation : react์™€๋Š” ์–ด๋–ค ๊ฒƒ์ด ๋‹ค๋ฅธ์ง€ ํŠน์ง• ์‚ดํŽด๋ณด๊ธฐ

(1) ์„ค์น˜ํ•˜๊ธฐ

npx create-next-app@latest
or
yarn create next-app


ํŠน๋ณ„ํ•œ ๊ฒƒ์ด ์—†๋‹ค๋ฉด ์œ„์™€ ๊ฐ™์ด ์„ธํŒ…ํ•˜๊ธฐ

(2) ๊ธฐ๋ณธ ํŒŒ์ผ
Next.js์—์„œ๋Š” layout.tsx, page.tsx์ด ๋‘ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ€์žฅ ๋งŽ์ด ๋‹ค๋ฃจ๊ฒŒ ๋  ๊ฒƒ์ž„

  1. layout.tsx
  • ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์ž„
  • children์„ ๊ฐ–๊ณ  ์žˆ์Œ
  1. page.tsx
    ์–˜ ๋˜ํ•œ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์ž„

  2. tailwind.config.ts / package.json ๋“ฑ ์—ฌ๋Ÿฌ ํŒŒ์ผ์ด ์„ธํŒ…๋ผ์žˆ์Œ

  3. build ํ›„ start๋ฅผ ํ•ด์ค˜์•ผ ํ•จ
    yarn build -> yarn start

  4. src > app > page.tsx ํŒŒ์ผ์ด UI๋ฅผ ํ•ธ๋“ค๋งํ•˜๋Š” ์ฃผ ํŒŒ์ผ์ด๋‹ค


๐Ÿ“– 02. ๋ผ์šฐํŒ…์„ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•œ ์ฃผ์š” ์šฉ์–ด

(1) Tree ๊ด€๋ จ

  • Tree

    • ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ์ž˜ ๋ณด๊ธฐ ์œ„ํ•œ ๊ทœ์น™(์œ„โžก๏ธ์•„๋ž˜). DOM Tree์™€ ๋น„์Šท
  • Subtree

    • tree์˜ ํ•œ ๋ถ€๋ถ„
    • root๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ leaf๋“ค์— ์ด๋ฅด๊ธฐ๊นŒ์ง€์˜ ๋ฒ”์œ„
  • Root

    • Tree ๋˜๋Š” Subtree์˜ ์ฒซ ๋ฒˆ์งธ ๋…ธ๋“œ
    • root layout ๊ฐ™์€ ๊ฒƒ์ด ๋จ
  • Leaf

    • children์ด ๋”์ด์ƒ ์—†๋Š” node๋ฅผ ๋งํ•จ


๐Ÿ“– 03. ํŒŒ์ผ(ํด๋”) ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ…

(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์— ํฌํ•จ์ด ๋˜๋Š”๋ฐ, ๊ทธ๋Ÿฌ๊ณ  ์‹ถ์ง€ ์•Š์„ ๋•Œ๋Š” ๊ฐ„๋‹จํ•˜๊ฒŒ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ

์ง์ ‘ ํ•ด๋ณธ ๊ฒฐ๊ณผ

์ž˜ ๋‚˜์˜ด

๐Ÿ“–04. ํŠน๋ณ„ํ•œ ํŒŒ์ผ๋“ค

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๋ฅผ ์‚ฌ์šฉํ•  ๋• ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋จ

  1. ํŠน์ • segment ์ดํ•˜์˜ route์—์„œ ์ ์šฉ๋ฐ›์„ layout UI๋ฅผ ํ•ด๋‹น ํด๋” ์•ˆ์— ๋งŒ๋“ฌ

  2. 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>
     )
    }
  3. ์šฐ๋ฆฐ ๋งŒ๋“  ์ ์ด ์—†์ง€๋งŒ, Next.js ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋‚˜๋ฉด ์ด๋ฏธ root ๊ฒฝ๋กœ์— layout.tsx ํŒŒ์ผ์ด ์กด์žฌํ•จ

ํ•ด๋‹น ์ฝ”๋“œ์—์„œ 8๋ฒˆ์งธ ์ค„ title์˜ ๋‚ด์šฉ์„ ๋ฐ”๊พธ๋ฉด ์‚ฌ์ดํŠธ ์ œ๋ชฉ์ด ๋ฐ”๋€œ

๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น return ๋ฌธ์—์„œ ์Šคํƒ€์ผ์„ ์ ์šฉํ•˜๋ฉด ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์˜ํ–ฅ์„ ๋ฐ›์Œ

(2) template
template ํŒŒ์ผ์€ layout๊ณผ ์œ ์‚ฌํ•œ ์ปดํฌ๋„ŒํŠธ์ž„.
๊ทธ๋ž˜์„œ ์ด ๋‘ ์š”์†Œ๋Š” ๋Š˜ ๋น„๊ต๋Œ€์ƒ์ด ๋จ.
๊ฐ€์žฅ ๋‘๋“œ๋Ÿฌ์ง€๋Š” ์ฐจ์ด๋Š”

์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋Š”๊ฐ€? ๋ฆฌ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚˜๋Š”๊ฐ€?

๊ฒฝ๋กœ ์ „๋ฐ˜์— ๊ฑธ์ณ์„œ ์ƒํƒœ๊ฐ€ ์œ ์ง€๋˜๋Š” layout๊ณผ ๋‹ฌ๋ฆฌ template์€ ๋ผ์šฐํŒ…์„ ํƒ์ƒ‰ํ•  ๋•Œ ๊ฐ ํ•˜์œ„ ํ•ญ๋ชฉ์— ๋Œ€ํ•ด ์ƒˆ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ฌ. ์ฆ‰, ์œ ์ € ์ž…์žฅ์—์„œ ๋™์ผํ•œ Template์„ ๊ณต์œ ํ•˜๋Š” ๊ฒฝ๋กœ ์‚ฌ์ด๋ฅผ ์™”๋‹ค๊ฐ”๋‹ค ํ•  ๋•Œ DOM ์š”์†Œ๊ฐ€ ๋‹ค์‹œ ์ƒ์„ฑ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•จ

(2)-1. use-case

  1. template์„ ํ†ตํ•œ ํŽ˜์ด์ง€ open animation
    • ํŽ˜์ด์ง€ ๊ฐ„ ์ „ํ™˜ ์‹œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๊ณ„์†ํ•ด์„œ ์ฃผ๊ณ  ์‹ถ์„ ๋•Œ
    • layout์œผ๋กœ ๋งŒ๋“ค์–ด ๋†“์œผ๋ฉด, ์ตœ์ดˆ ๋ Œ๋”๋ง ์‹œ์—๋งŒ animation์ด ์ ์šฉ๋˜๊ณ  ๋๋‚จ
  1. useEffect, useState์— ์˜์กดํ•˜๋Š” ๊ธฐ๋Šฅ
    • layout : console.log๊ฐ€ ์ตœ์ดˆ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ
    • template : ํŽ˜์ด์ง€ ์ด๋™ ์‹œ ๋งˆ๋‹ค ๊ณ„์† ํ˜ธ์ถœ

๊ฒฐ๋ก  : ํŠน์ •ํ•œ ์ด์œ ๊ฐ€ ์žˆ์ง€ ์•Š๋Š” ํ•œ, 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" />
  1. ๊ฒ€์ƒ‰ ์—”์ง„์— ์ด๋ฏธ์ง€ ๋‚ด์šฉ ์„ค๋ช…ํ•˜๊ธฐ: alt ํ…์ŠคํŠธ๋Š” ๊ฒ€์ƒ‰ ์—”์ง„์— ์ด๋ฏธ์ง€์˜ ๋‚ด์šฉ๊ณผ ๋งฅ๋ฝ์„ ์„ค๋ช…ํ•ด ์คŒ. ํ…์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์ด๋ฏธ์ง€๊ฐ€ ๋ฌด์—‡์— ๊ด€ํ•œ ๊ฒƒ์ธ์ง€ ์ดํ•ดํ•˜๊ณ , ๊ด€๋ จ ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ๋กœ ํ•ด๋‹น ์ด๋ฏธ์ง€๋ฅผ ๋” ์ •ํ™•ํ•˜๊ฒŒ ๋žญํ‚นํ•  ์ˆ˜ ์žˆ์Œ
  1. ์ ‘๊ทผ์„ฑ ํ–ฅ์ƒ: alt ํ…์ŠคํŠธ๋Š” ์‹œ๊ฐ ์žฅ์• ๊ฐ€ ์žˆ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์›น์‚ฌ์ดํŠธ์˜ ์ด๋ฏธ์ง€ ์ฝ˜ํ…์ธ ๋ฅผ ์ดํ•ดํ•˜๋Š” ๋ฐ ๋„์›€์„ ์คŒ. ์ด๋Ÿฌํ•œ ์ ‘๊ทผ์„ฑ ๊ฐœ์„ ์€ ๊ฒ€์ƒ‰ ์—”์ง„์— ์˜ํ•ด ๊ธ์ •์ ์ธ ์‹ ํ˜ธ๋กœ ํ•ด์„๋˜์–ด ์ „๋ฐ˜์ ์ธ ์‚ฌ์ดํŠธ์˜ SEO ์ ์ˆ˜๋ฅผ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Œ

Next.js์—์„œ๋Š” Config-based MetaData๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Œ

  1. static
    • page.tsx ๋˜๋Š” layout.tsx ์–ด๋””๋“ ์ง€
         export const metadata: Metadata = {
      	title: "Sparta Next App",
      	description: "This is awesome Website",
      }
      ๋ฅผ ์‚ฝ์ž…ํ•ด๋†“๊ธฐ๋งŒ ํ•˜๋ฉด ์ ์šฉ์ด ๋จ
    • ์—ฌ๊ธฐ์„œ ๊ธฐ์–ตํ•ด์•ผ ํ•  ๊ฒƒ
      • metadata in page.tsx: ํ•ด๋‹น page.tsx ์ปดํฌ๋„ŒํŠธ์—๋งŒ ์ ์šฉ
      • metadata in layout.tsx: ํ•ด๋‹น layout์˜ ํ•˜์œ„ ์š”์†Œ์— ๋ชจ๋‘ ์ ์šฉ
  1. 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;

๐Ÿ“– 05. ํŽ˜์ด์ง€ ์ด๋™๊ณผ ๊ด€๋ จ๋œ ๊ธฐ๋Šฅ ๋ชฉ๋ก

(1) Link

Next.js๋Š” <Link>๋ผ๋Š” ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ œ๊ณต. <Link> ํƒœ๊ทธ๋Š” ๊ธฐ๋ณธ HTML์˜ aํƒœ๊ทธ๋ฅผ ํ™•์žฅํ•œ ๊ฐœ๋…

1. Link ํƒœ๊ทธ๋Š” prefetching์„ ์ง€์›

  • Next.js์˜ >Link> ์ปดํฌ๋„ŒํŠธ๋Š” ๋ทฐํฌํŠธ์— ๋งํฌ๊ฐ€ ๋‚˜ํƒ€๋‚˜๋Š” ์ˆœ๊ฐ„ ํ•ด๋‹น ํŽ˜์ด์ง€์˜ ์ฝ”๋“œ์™€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์˜ค๋Š” ํ”„๋ฆฌํŽ˜์นญ ๊ธฐ๋Šฅ์„ ์ง€์›ํ•จ. ์‚ฌ์šฉ์ž๊ฐ€ ๋งํฌ๋ฅผ ํด๋ฆญํ–ˆ์„ ๋•Œ ๊ฑฐ์˜ ์ฆ‰์‹œ ํŽ˜์ด์ง€๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Œ

2. Link ํƒœ๊ทธ๋Š” Route ์‚ฌ์ด์— client-side navigation์„ ์ง€์›

  • <Link> ์ปดํฌ๋„ŒํŠธ๋Š” ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ƒˆ ํŽ˜์ด์ง€๋ฅผ ๋กœ๋“œํ•˜๊ธฐ ์œ„ํ•ด ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๋Œ€์‹ , ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ํŽ˜์ด์ง€๋ฅผ ๋ฐ”๊ฟ”์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ํŽ˜์ด์ง€ ์ „ํ™˜ ์‹œ ๋งค์šฐ ๋น ๋ฅธ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜(UX)๋ฅผ ์ œ๊ณต
  • ํŽ˜์ด์ง€์˜ HTML์„ ์„œ๋ฒ„์—์„œ ๋‹ค์‹œ ๊ฐ€์ ธ์˜ฌ ํ•„์š” ์—†์ด, ํ•„์š”ํ•œ JSON ๋ฐ์ดํ„ฐ๋งŒ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๊ฐ€์ ธ์™€์„œ ํด๋ผ์ด์–ธํŠธ์—์„œ ํŽ˜์ด์ง€๋ฅผ ์žฌ๊ตฌ์„ฑํ•˜์—ฌ ๋ Œ๋”๋ง

(2) useRouter

1. aํƒœ๊ทธ vs Link vs Router

  • aํƒœ๊ทธ

    • ์ˆœ์ˆ˜ HTML ์š”์†Œ
    • ์™„์ „ํ•œ ์ƒˆ ํŽ˜์ด์ง€๋กœ ์ „ํ™˜์„ ์›ํ•  ๋•Œ : ํŽ˜์ด์ง€๋Š” ์™„์ „ํžˆ ์ƒˆ๋กœ๊ณ ์นจ
    • ๋นˆ ํ™”๋ฉด ๋ณด์ผ ์ˆ˜ ์žˆ์Œ โžก๏ธ UX๊ฐ€ ์ข‹์ง€ ์•Š์Œ
    • Next.js์—์„  ๊ฑฐ์˜ ์•ˆ ์”€
  • Linkํƒœ๊ทธ

    • Link ํƒœ๊ทธ๋Š” aํƒœ๊ทธ๋ฅผ ๋งŒ๋“ค์–ด๋‚ด๊ธฐ ๋•Œ๋ฌธ์— SEO๊ฐ€ ์œ ๋ฆฌ
    • ํด๋ฆญ ์ฆ‰์‹œ ํŽ˜์ด์ง€ ์ด๋™
  • Router(useRouter)

    useRouter๋ฅผ ์‚ฌ์šฉํ•  ๋• ํ•ญ์ƒ ์ฝ”๋“œ ์ตœ์ƒ๋‹จ์— "use client"๋ฅผ ์‚ฝ์ž…ํ•ด์•ผ ํ•จ

    • aํƒœ๊ทธ๋ฅผ ์•Œ์•„์ฐจ๋ฆด ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ํฌ๋กค๋Ÿฌ ์ž…์žฅ์—์„œ๋Š” ํ•ด๋‹น ์š”์†Œ๊ฐ€ '์ด๋™์„ ์›ํ•œ๋‹ค' ๋ผ๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์—†์Œ โžก๏ธ SEO ๋ถˆ๋ฆฌ
    • ๋Œ€๋ถ€๋ถ„ onClick ๊ฐ™์€ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์—์„œ ์‚ฌ์šฉ
    • ํด๋ฆญ ํ›„ ๋กœ์ง์˜ ์ˆœ์„œ์— ๋”ฐ๋ผ ์‹คํ–‰ โžก๏ธ ์ฆ‰์‹œ ์ด๋™ ์•ˆ๋จ

2. router.push (replace, back, reload)

history stack์„ ์•Œ์•„์•ผ ํ•จ. ์‹ค์ œ๋กœ history stack์€ ํ•œ ๊ฐœ๋ผ๊ณ  ์ดํ•ดํ•ด์•ผ ํ•จ

  • history stack์€ ๋ฐฉ๋ฌธ์ž์˜ ํŽ˜์ด์ง€ ๋ฐฉ๋ฌธ ์ˆœ์„œ๋ฅผ ๊ธฐ๋กํ•˜๋Š” ์‹œ์Šคํ…œ
  • ํŽ˜์ด์ง€ ์ด๋™ โžก๏ธ URL์ด history stack์— ์ถ”๊ฐ€
  • EX: ๋’ค๋กœ ๊ฐ€๊ธฐ, ์•ž์œผ๋กœ ๊ฐ€๊ธฐ ํ–ˆ์„ ๋•Œ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋Š” ์ด์œ 
  1. router.push

    • ์ƒˆ๋กœ์šด URL์„ ํžˆ์Šคํ† ๋ฆฌ ์Šคํƒ์— ์ถ”๊ฐ€
    • ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•˜๋ฉด URL์ด ํžˆ์Šคํ† ๋ฆฌ ์Šคํƒ์˜ ๋งจ ์œ„์— ์Œ“์ž„
    • ๋’ค๋กœ ๊ฐ€๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, ์Šคํƒ์—์„œ ๊ฐ€์žฅ ์ตœ๊ทผ์— ์ถ”๊ฐ€๋œ URL๋กœ๋ถ€ํ„ฐ ์ด์ „ ํŽ˜์ด์ง€๋กœ ๋Œ์•„๊ฐ
  2. router.replace

    • ํ˜„์žฌ URL์„ ํžˆ์Šคํ† ๋ฆฌ ์Šคํƒ์—์„œ ์ƒˆ๋กœ์šด URL๋กœ ๋Œ€์ฒด
    • ๋’ค๋กœ ๊ฐ€๊ธฐ ํด๋ฆญ ์‹œ ์ด์ „ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜์ง€๋งŒ, ๊ต์ฒด๋œ ํŽ˜์ด์ง€๋กœ๋Š” ๋Œ์•„๊ฐˆ ์ˆ˜ ์—†์Œ
    • ํ˜„์žฌ ํŽ˜์ด์ง€๋ฅผ ํžˆ์Šคํ† ๋ฆฌ์—์„œ ์™„์ „ํžˆ ๋Œ€์ฒด
  3. router.back

    • ์‚ฌ์šฉ์ž๋ฅผ ํžˆ์Šคํ† ๋ฆฌ ์Šคํƒ์—์„œ ํ•œ ๋‹จ๊ณ„ ๋’ค๋กœ ์ด๋™
    • ๋’ค๋กœ ๊ฐ€๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญํ•œ ๊ฒƒ๊ณผ ๊ฐ™์€ ํšจ๊ณผ
  4. router.reload

    • ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ๊ณ ์นจ
    • ํžˆ์Šคํ† ๋ฆฌ ์Šคํƒ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Œ. ํŽ˜์ด์ง€์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ตœ์‹  ์ƒํƒœ๋กœ ์—…๋ฐ์ดํŠธ ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉ
profile
๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜๊ณ  ์‹ถ์–ด~~~

0๊ฐœ์˜ ๋Œ“๊ธ€