Skip to content

๐Ÿ“š NextJS (๊ธฐ๋ณธ/์‹ฌํ™”) ๋‚ด์šฉ ์ •๋ฆฌ ~ing

leemember/NextJS

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

32 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

NextJS

๐Ÿ“š NextJS study

์Šคํ„ฐ๋”” ์ง„ํ–‰ ๋ฐฉ์‹

  • Next.js ๊ธฐ๋ณธ ํ•™์Šต
  • ๊ฐ„๋‹จํ•œ ํ† ์ด ํ”„๋กœ์ ํŠธ ๋งŒ๋“ค์–ด๋ณด๊ธฐ
  • Next.js ์‹ฌํ™” ํ•™์Šต
  • ํฌํŠธํด๋ฆฌ์˜ค ๋Œ€๋น„ ์ปค๋จธ์Šค ์„œ๋น„์Šค ์ œ์ž‘

๐Ÿ“ ํ”„๋ ˆ์ž„์›Œํฌ vs ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

  • ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ๊ธฐ๋ฐ˜๊ตฌ์กฐ vs ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๊ฐœ๋ฐœ ํŽธ์˜ ๋„๊ตฌ๋“ค
  • ์ œ์–ด ์ฃผ๋„๊ถŒ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๊ฐ€์ง vs ์ œ์–ด ์ฃผ๋„๊ถŒ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ€์ง
  • ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ๊ธฐ๊ณ„ (like ๊ตด์‚ญ๊ธฐ) vs ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๊ณต๊ตฌ (like ํŽœ์น˜๋‹ˆํผ)
  • ํ”„๋ ˆ์ž„์›Œํฌ ์ž์œ ๋„ ์ƒ๋Œ€์ ์œผ๋กœ ์ž‘์Œ vs ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž์œ ๋„ ์ƒ๋Œ€์ ์œผ๋กœ ํผ

๐Ÿ“ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์žฅ์ 

  • ๊ฐœ์ธ์ด ํ•ด์•ผํ•  ๊ณ ๋ฏผ๋“ค์„ ํ”„๋ ˆ์ž„์›Œํฌ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ฏธ๋ฆฌ ํ•˜๊ณ  ๋ฐ˜์˜
  • ํŠน์ • ๋””์ž์ธ ํŒจํ„ด์ด๋‚˜ ๋™์ž‘๊ณผ ๊ธฐ๋Šฅ๋“ค์„ ์œ„ํ•œ ์ •์˜์™€ ๋ฐฉ์‹์„ ์ •๋ฆฌํ•ด๋‘ 
  • ์—ฌ๋Ÿฌ ๊ฐœ๋ฐœ์ž๊ฐ€ ํ•จ๊ป˜ ํ˜‘์—…ํ•  ๋•Œ ๊ธฐ์ค€์ ์ด ๋จ

๐Ÿง ์™œ ๋งŽ์€ ํ”„๋ ˆ์ž„์›Œํฌ ์ค‘ Next๋ฅผ ์‚ฌ์šฉํ• ๊นŒ ?

  • ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋“ค์ด ๊ฐ€์ง„ ๊ณ ๋ฏผ์— ๋Œ€ํ•œ ์ ์ ˆํ•œ ํ•ด๊ฒฐ์ฑ…์„ ์ œ๊ณตํ•ด์ค€๋‹ค.
    • ๊ทœ๋ชจ๊ฐ€ ์žˆ๋Š” ์„œ๋น„์Šค ๊ตฌ์กฐ ์„ค๊ณ„๋ฅผ ์–ด๋–ป๊ฒŒ ํ•  ๊ฒƒ์ธ๊ฐ€ ?
    • ๊ฐœ๋ฐœํ™˜๊ฒฝ / ์ฝ”๋“œ ๋ถ„ํ•  / ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ ๋“ฑ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ๋“ค์„ ์ œ๊ณตํ•ด์ค€๋‹ค.
    • SEO ๊ฒ€์ƒ‰ ์—”์ง„ ์ตœ์ ํ™” (์‚ฌ์šฉ์ž๋“ค์ด ํ›จ์”ฌ ๋” ์‰ฝ๊ฒŒ ์›น์„œ๋น„์Šค๋ฅผ ์ฐพ์•„๊ฐˆ ์ˆ˜ ์žˆ๋„๋ก)
    • ํ”„๋ก ํŠธ์—”๋“œ์— ํ•„์š”ํ•œ ๊ฐ„๋‹จํ•œ API ๊ตฌ์„ฑ
    • ์†์‰ฌ์šด ๋ฐฐํฌ ์‹œ์Šคํ…œ Vercel

Next.js ํ”„๋กœ์ ํŠธ ๋„์šฐ๊ธฐ

npx create-next-app nextjs-blog --use-npm --example "https://github.com/vercel/next-learn/tree/master/basics/learn-starter"

--example ๋’ค์—์žˆ๋Š” github url์„ ์˜ˆ์ œ๋กœ ๋ ˆํฌ๋ฅผ ๋”ธ ๊ฒƒ์ด๋‹ค ๋ผ๋Š” ๋ช…๋ น์–ด ๋œป์ด๋‹ค.

๐ŸŒŸ ์‹คํ–‰

  cd nextjs-blog
  npm run dev = yarn dev (๋™์ผ ๋ช…๋ น์–ด)
  ํ•ด๋‹น ํ”„๋กœ์ ํŠธ์—์„œ yarn ์„ค์น˜ํ•จ

turbo๋ผ๋Š” ๊ฑธ๋กœ mono repo ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

next.js์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ๋“ค

  • ์ฝ”๋“œ๋“ค์€ ๊ณ ์น˜๋Š”๋Œ€๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค (= fast refresh)
  • pages/product/[slug] ๋ผ๋Š” ํ‘œ๊ธฐ๊ฐ€ wildcard๋กœ ๋™์ž‘ํ•˜๋‚˜๋ณด๋‹ค
    • ๋‹ค์ด๋‚˜๋ฏนํ•˜๊ฒŒ path๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.
  • api ์š”์ฒญ์„ ์–ด๋””๋ก ๊ฐ€ ํ•˜๊ณ  ์‘๋‹ต์„ ๋ฐ›๋Š”๋‹ค.
    • api์— ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต๋“ค์„ ์ฝ”๋“œ์—์„œ ์กฐํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

data fetching

ํ™”๋ฉด์— ๋ฌด์–ธ๊ฐ€๋ฅผ ๊ทธ๋ฆฌ๋ ค๋ฉด ๊ฒฐ๊ตญ ์–ด๋””์„ ๊ฐ€ data๋ฅผ ๊ฐ€์ ธ์™€์•ผํ•œ๋‹ค. (=์ด๊ฒŒ ํ”„๋ก ํŠธ์—”๋“œ์˜ ์—ญํ• )

  • next๊ฐ€ ์ œ์‹œํ•˜๋Š” 4๊ฐ€์ง€ ๋ฐ์ดํ„ฐ ํŒจ์นญ ๋ฐฉ๋ฒ•
  1. SSR
  2. CSR
  3. SSG
  4. ISR

๐Ÿ”ด SSR (์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง)

  • ์„œ๋ฒ„๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ ๊ทธ๋ฆฐ๋‹ค.
  • SSR์„ ๋‹ด๋‹นํ•˜๋Š” ํ•จ์ˆ˜ : getServerSideProps
export async function getServerSideProps() {
  console.log('server');

  return {
    props: { time: new Date().toISOString() },
  };
}

์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ํŽ˜์ด์ง€์—๋‹ค๊ฐ€ props๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ ๋ฐ›์•˜๋‹ค.

image

์™ผ์ชฝ์— ์‹œ๊ฐ„์ด ์ฐํžŒ ํฐ ๋ฐฐ๊ฒฝ์€ ์›น๋ธŒ๋ผ์šฐ์ €์ž…๋‹ˆ๋‹ค. ์˜ค๋ฅธ์ชฝ์€ ์ž‘์—…ํ•œ ์†Œ์Šค์ฝ”๋“œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋ ค์ฃผ๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜๋Š” ๊ณผ์ •์œผ๋กœ ๋ดค์„ ๋•Œ server ๋ผ๋Š” ์ฝ˜์†”๋กœ๊ทธ ๋ฉ”์‹œ์ง€๊ฐ€ ํ„ฐ๋ฏธ๋„ ์ฐฝ์—์„œ ๋ณด์—ฌ์ง€๊ณ  ์žˆ๋‹ค.


๐ŸŸก CSR (Client Side Render)

  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ ๊ทธ๋ฆฐ๋‹ค.
  • ๊ธฐ์กด ๋ฆฌ์•กํŠธ ์‚ฌ์šฉ๋ฒ•๊ณผ ๋™์ผํ•˜๋‹ค.

image

์™ผ์ชฝ์— ์‹œ๊ฐ„์ด ์ฐํžŒ ํฐ ๋ฐฐ๊ฒฝ์€ ์›น๋ธŒ๋ผ์šฐ์ €์ž…๋‹ˆ๋‹ค. ์˜ค๋ฅธ์ชฝ์€ ์ž‘์—…ํ•œ ์†Œ์Šค์ฝ”๋“œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

ํด๋ผ์ด์–ธํŠธ๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ทธ๋ ค์ฃผ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์›น๋ธŒ๋ผ์šฐ์ €์— ์žˆ๋Š” ์ฝ˜์†”๋กœ๊ทธ์—์„œ 'client' ๋ผ๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ํ™•์ธํ•ด ๋ณผ ์ˆ˜ ์žˆ๋‹ค.


๐ŸŸ  SSG (Statice-Site Generation)

  • ์ •์ ์ธ ์‚ฌ์ดํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค : ์ •์ ์ธ ์‚ฌ์ดํŠธ๋ฅผ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ ๊ทธ๋ ค์ค€๋‹ค.
  • SSG์„ ๋‹ด๋‹นํ•˜๋Š” ํ•จ์ˆ˜๋กœ๋Š” getStaticProps๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค.
  • ์–ธ์ œ์“ฐ์ด๋‚˜ ? ๋ธ”๋กœ๊ทธ ๊ฐ™์ด ์ •์ ์ผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๋“ค์„ ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•œ๋‹ค.

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-01-13 แ„‹แ…ฉแ„’แ…ฎ 11 13 20

SSG ๊ฐ€ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜๊ณ ์ž ํ•œ๋‹ค๋ฉด yarn build ๊ณผ์ •์„ ๊ฑฐ์นœ ํ›„์— yarn run dev๋ฅผ ํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  path ์ฃผ์†Œ ssr ํŽ˜์ด์ง€์— ์ง„์ž…ํ–ˆ์„ ๋•Œ, console.log๊ฐ€ ํ„ฐ๋ฏธ๋„์—๋„ ์›น๋ธŒ๋ผ์šฐ์ € ์ƒ์— ์žˆ๋Š” ์ฝ˜์†” ์ฐฝ ๊ทธ ์–ด๋””์—๋„ ๋‚˜ํƒ€๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


๐ŸŸข ISR (Incremental Static Regeneration)

  • ์ฆ๋ถ„ ์ •์  ์‚ฌ์ดํŠธ๋ฅผ ์žฌ์ƒ์„ฑ ํ•œ๋‹ค. (ํŠน์ • ์ฃผ๊ธฐ๋กœ) ์ •์ ์ธ ์‚ฌ์ดํŠธ์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ ๋‹ค์‹œ ๊ทธ๋ ค์ค€๋‹ค.
  • ์ด๊ฑธ ๋‹ด๋‹นํ•˜๋Š” ํ•จ์ˆ˜๋Š” getStaticProps ๋ผ๋Š” ํ•จ์ˆ˜๋‹ค. ๊ฐ’์„ ๋ฆฌํ„ดํ•˜๋ฉด์„œ ๋™์ž‘ํ•œ๋‹ค.
export async function getStaticProps() {
  console.log("server");

  return {
    props: { time: new Date().toISOString() },
    revalidate: 1, // ๐Ÿ“ 1์ดˆ ๋‹จ์œ„๋กœ => ์ด ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด์„œ ๊ฐ’์„ ๋ฆฌํ„ดํ•ด์„œ ๋‹ค์‹œ ๊ทธ๋ ค์ค€๋‹ค.
  };
}

์„œ๋ฒ„๊ฐ€ 1์ดˆ ๊ฐ„๊ฒฉ์œผ๋กœ ๋ฆฌํ„ด๋œ๋‹ค. ์–ด๋–ค ์ œํ’ˆ์„ ๊ณ„์† ํŒ๋งคํ•˜๊ณ  ๊ทธ ์ œํ’ˆ์˜ ์ •๋ณด๋ฅผ ๊ณ„์† ์—…๋ฐ์ดํŠธ๋ฅผ ํ•œ๋‹ค๊ณ  ํ•  ๊ฒฝ์šฐ ์ด๋Ÿฐ ํ•จ์ˆ˜๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์—…ํ•  ์ˆ˜๊ฐ€ ์žˆ๋‹ค. (ex) ์‡ผํ•‘๋ชฐ์—์„œ ์ž์ฃผ ์‚ฌ์šฉ


๐Ÿ”ต Data Fetching ๋ฐ์ดํ„ฐ ํŒจ์นญ์— ๋Œ€ํ•œ ๋‚ด์šฉ ์š”์•ฝ

  • ํŽ˜์ด์ง€๋ฅผ ๊ทธ๋ฆฌ๋Š” ๋ฐฉ์‹ : ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ ๊ทธ๋ฆฐ๋‹ค.
  • SSR / CSR / SSG / ISG : ์ด 4๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ํŒจ์นญํ•œ๋‹ค.
  • SSG : yarn dev ๋กœ๋Š” SSR ์ฒ˜๋Ÿผ ๋™์ž‘ํ•œ๋‹ค.
  • SSR์€ ์„œ๋ฒ„ ๋ถ€ํ•˜๊ฐ€ ์ผ์–ด๋‚˜๋‹ˆ ํ•„์š”์— ๋”ฐ๋ผ SSG์™€ ISR์„ ์ ์ ˆํ•˜๊ฒŒ ์“ฐ๋ฉด ์ข‹๋‹ค.

๐Ÿฅ Layout / Pages / Image

  • Pre-rendering : SEO ์™€ ์ดˆ๊ธฐ ๋กœ๋”ฉ ์†๋„
  • SSG vs SSR : SSG์€ ๋นŒ๋“œ ์‹œ / SSR์€ ์š”์ฒญ ์‹œ
  • Layout : pages/_app.js ํ™œ์šฉํ•ด์„œ ํŽ˜์ด์ง€ ๊ณตํ†ตํ™”
  • Images : ์ตœ์ ํ™”๋œ ์ด๋ฏธ์ง€ ํ™œ์šฉ util



์ž‘์—… ๋“ค์–ด๊ฐ€๊ธฐ ์ „, Prettier ์„ค์ •

$yarn prettier-fix
  • yarn add -D prettier // prettier ์ถ”๊ฐ€
  • .prettierrc // ํŒŒ์ผ ์ถ”๊ฐ€
  • ํŒจํ‚ค์ง€์— prettier-fix ๋ช…๋ น ์ถ”๊ฐ€

๐Ÿ” Next๊ธฐ๋ฐ˜์œผ๋กœ ๋ผ์šฐํ„ฐ ํ•˜๋Š” ๋ฒ•

  • Next.js์˜ Router๋Š” file-systems ๊ธฐ๋ฐ˜์ด๋‹ค.
  • pages/ ํ˜น์€ src/pages/
  • pages/index.js ์™€ src/pages/index.js ๋‘˜ ๋‹ค ์žˆ๋‹ค๋ฉด ์šฐ์„ ์ˆœ์œ„๋Š” pages/index.js ๊ฐ€ ๋จผ์ €๋‹ค. ํ•˜์ง€๋งŒ ๊ฐœ๋ฐœํ•  ๋•Œ ์ต์ˆ™ํ•œ ํ™˜๊ฒฝ์œผ๋กœ๋Š” ํ›„์ž์ด๊ธด ํ•˜๋‹ค.

Slug

pages/caategory/[slug].js => /category/:slug (ex. /category/food) ์ด๋Ÿฐ์‹์œผ๋กœ category ๋’ค์— ์•„๋ฌด ๋‹จ์–ด ์ง‘์–ด๋„ฃ์–ด๋„ ํ•ด๋‹น ๊ฒฝ๋กœ๋กœ ์ด๋™๋œ๋‹ค.

pages/[usename]/info.js => /:usename/info (ex. /jimmy/info) ์ด๊ฒƒ๋„ [usename] ๋ถ€๋ถ„์— ์•„๋ฌด ๋‹จ์–ด ์ง‘์–ด๋„ฃ์–ด๋„ ํ•ด๋‹น ๊ฒฝ๋กœ๋กœ ์ด๋™๋œ๋‹ค
  • ํŒŒ์ผ์—๋„ slug๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ณ , ํด๋”์—๋„ slug๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

...slug

pages/cart/[...slug].js => /cart/* (ex. /cart/2022/06/04)
  • ...์„ ์“ฐ๋ฉด depth๊ฐ€ ๋ฌดํ•œ์œผ๋กœ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๋ชจ๋“  ๊ฑธ ๋‹ค ๋ฐ›์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

๋ผ์šฐํŒ… ์ •๋ฆฌ

  • Router -> file ststems์„ ํ† ๋Œ€๋กœ ๊ตฌํ˜„
  • pages/ ํ˜น์€ src/pages -> pages/ ๊ฐ€ ์šฐ์„ ์ˆœ์œ„, ํ•˜๋‚˜๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ํ”„๋กœ์ ํŠธ ์„ค์ • -> prettier / jsoncofig.json(์ ˆ๋Œ€๊ฒฝ๋กœ ๋ณ€๊ฒฝ)
  • Slug -> ๋‹ค์–‘ํ•œ ์œ„๊ณ„์˜ ๋‹ค์ด๋‚˜๋ฏน ์ œ๊ณตํ•ด์ค€๋‹ค.



๐Ÿ”ฎ Dynamic Routes

  • [slug] ๊ฐ’์€ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•  ๊ฒƒ ์ธ๊ฐ€? ex) pages/category/[slug].js
import {useRouter} from 'next/router;

const router = useRouter();
const {slug} = router.query;
  • ์ด์ฒ˜๋Ÿผ router.query์˜ slug๋ฅผ ์“ฐ๋ฉด url์— /category/{slug}์— ์žˆ๋Š” {slug}์— ์ž…๋ ฅํ•œ ๊ฐ’์ด ํ™”๋ฉด์— ์ฐํžŒ๋‹ค.

๐Ÿ’ก query(== ?) ์ถ”๊ฐ€

import { useRouter } from 'next/router'

export default function CategorySlug() {
  const router = useRouter()
  const { slug, from } = router.query

  return (
    <h1 className="title">
      Category {slug} from {from}
    </h1>
  )
}

CategorySlug.getLayout = function getLayout(page) {
  return <>{page}</>
}
  • category/sports?from=event ๋ผ๋Š” url์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ, url์—์„œ๋Š” ?๋ฅผ ์ฟผ๋ฆฌ๋ผ๊ณ  ํ•œ๋‹ค. ์ด ์ฟผ๋ฆฌ ๊ธฐ์ค€์œผ๋กœ from์— ๋ฌด์—‡์ด ๋‹ด๊ฒผ๋Š”์ง€ ๊ทธ์— ๋งž๋Š” ๊ฐ’์„ ๋‹ค ๋ฐ›์•„ ๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-01-27 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 11 51 40

์ด์™€๊ฐ™์ด url ๋’ค์— event๋ฅผ ๋„ฃ๊ฒŒ ๋˜๋ฉด ํ™”๋ฉด์—๋„ ๋™์ผํ•˜๊ฒŒ {from} ๊ฐ’์ด ์ฐํžˆ๊ฒŒ ๋œ๋‹ค.


๐Ÿ–๏ธ ๋‹ค์ค‘ ์Šฌ๋Ÿฌ๊ทธ

  • pages/cart/[...slug].js
const {slug} = router.query;

์—ฌ๊ธฐ์„œ slug๋Š” ๋ฐฐ์—ด์ด๋‹ค.

  • ๊ฒฝ๋กœ : pages/cart/[...date].js
import { useRouter } from 'next/router'

export default function CartDateSlug() {
  const router = useRouter()
  const { date } = router.query

  return (
    <>
      <h1 className="title">CartDate Slug {JSON.stringify(date)}</h1>
    </>
  )
}

CartDateSlug.getLayout = function getLayout(page) {
  return <>{page}</>
}

์ด์ฒ˜๋Ÿผ url์— ๋‹ค์ค‘ ์Šฌ๋Ÿฌ๊ทธ๋“ค์„ ์ „๋ถ€ ํ™”๋ฉด์— ๋ฟŒ๋ ค์ค€๋‹ค. JSON.stringify๋กœ ๊ฐ์Œ‹๊ธฐ ๋–„๋ฌธ์— "" ๋ฌธ์ž์—ด์˜ ํ˜•์‹์œผ๋กœ ๋ฐฐ์—ด ์•ˆ์— ๊ฐ’์ด ๋‹ด๊ฒจ ๋‚˜์˜จ๋‹ค.

  • ์˜ต์…”๋„ํ•˜๊ฒŒ ์Šฌ๋Ÿฌ๊ทธ ๊ฐ’์ด ์—†์–ด๋„ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ ค๋ฉด [[...date]].js ์ด์ฒ˜๋Ÿผ ๋Œ€๊ด„ํ˜ธ๋ฅผ 2๋ฒˆ ๊ฐ์‹ธ๋ฉด ๋œ๋‹ค.


๐Ÿ–๏ธ Shallow Routing

  • getServerSideProps / getStaticProps ๋“ฑ์„ ๋‹ค์‹œ ์‹คํ–‰์‹œํ‚ค์ง€ ์•Š๊ณ , ํ˜„์žฌ ์ƒํƒœ๋ฅผ ์žƒ์ง€ ์•Š๊ณ  url ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ๋ฒ•

๐Ÿ‘€ ์ƒํƒœ๋Š” ์œ ์ง€ํ•˜๋ฉด์„œ URL๋งŒ ๋ฐ”๊พธ๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ ?

  • ์‚ฌ์šฉ์ž๊ฐ€ ์–ด๋–ค ๋™์ž‘์„ ํ–ˆ๊ณ , ๊ทธ ๊ธฐ๋ก์„ query๋กœ ๋‚จ๊ธฐ๊ณ  ์‹ถ์„๋•Œ (๐Ÿ‘‰ ์žฅ์  : query๋กœ ๋‚จ๊ธฐ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•ด๋„ ์œ ์ง€๋œ๋‹ค.)
  • ํŠน์ • ํŽ˜์ด์ง€ 10ํŽ˜์ด์ง€ ๊ฐ”๋‹ค๊ฐ€ ์ƒˆ๋กœ๊ณ ์นจ ํ•ด๋„ ๊ทธ๊ฒŒ ์œ ์ง€๋œ๋‹ค.
    (๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€๋‚˜ ์„ธ์…˜ ์Šคํ† ๋ฆฌ์ง€๋ฅผ ํ†ตํ•ด ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•ด๋„ ํŠน์ • ํŽ˜์ด์ง€์˜ ์œ„์น˜๋ฅผ ์œ ์ง€์‹œํ‚ฌ ์ˆ˜ ์žˆ์ง€๋งŒ query๋กœ ํ•ด๋„ ๊ทธ ์ƒํƒœ๊ฐ€ ์œ ์ง€๋˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.

์‚ฌ์šฉ์ž์˜ ํ–‰๋™์„ ๊ธฐ๋กํ•œ ํ–‰์œ„๋“ค์ด๋‹ค. ๊ทผ๋ฐ, url ์„ ๋ฐ”๊ฟจ๋‹ค๊ณ  ํ•ด์„œ 1๏ธโƒฃ ํŽ˜์ด์ง€๊ฐ€ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ๋ Œ๋” ๋œ๋‹ค๊ฑฐ๋‚˜ 2๏ธโƒฃ ์›์น˜ ์•Š๋Š” ๋ฐ์ดํ„ฐ ํŒจ์นญ๊นŒ์ง€ ๋œ๋‹ค๋ฉด ๋น„ํšจ์œจ์ ์ผ ์ˆ˜๊ฐ€ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ๐Ÿ‘‰ Shallow Routing ๐Ÿ‘ˆ์ด ํ•„์š”ํ•œ ๊ฒƒ์ด๋‹ค !

๐Ÿ–๏ธ Data fetching์„ ์ผ์œผํ‚ค๊ณ  ์‹ถ์ง€ ์•Š๋‹ค๋ฉด ?

  • url์„ ๋ฐ”๊พธ๋Š” 3๊ฐ€์ง€ ๋ฐฉ์‹์ด ์žˆ๋‹ค.
    • 1๏ธโƒฃ location.replace("url") : ๋กœ์ปฌ state ์œ ์ง€ ์•ˆ๋จ (re-render)
    • 2๏ธโƒฃ router.push(url) : ๋กœ์ปฌ state ์œ ์ง€ / data fetching์€ ์ผ์–ด๋‚จ โญ•๏ธ
    • 3๏ธโƒฃ router.push(url, as, {shallow: true}) : ๋กœ์ปฌ state ์œ ์ง€ / data fetching โŒ

์ด๊ฒƒ์— ๋Œ€ํ•œ ์˜ˆ์ œ๋Š” `/pages/settings/my/info.js` ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
      // 1๏ธโƒฃ ๋กœ์ปฌ state๋„ ์ƒˆ๋กœ ๋ฐ”๋€Œ๋ฉด์„œ ๋ฐ์ดํ„ฐ ํŒจ์นญ๋„ ๋‹ค์‹œ ๋˜๊ณ  ์•„์˜ˆ ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ ๋ถˆ๋ฅธ ๊ฒƒ๊ณผ ๊ฐ™๋‹ค.
      <button
        onClick={() => {
          alert('edit')
          setClicked(true)
          โบ๏ธ location.replace('/settings/my/info?status=editing')
        }}
      >
        edit(replace)
      </button>

      <br />

      // 2๏ธโƒฃ ๋กœ์ปฌ state๋Š” ์œ ์ง€๋˜์ง€๋งŒ, ๋ฐ์ดํ„ฐ ํŒจ์นญ์€ ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค.
      <button
        onClick={() => {
          alert('edit')
          setClicked(true)
          โบ๏ธ router.push('/settings/my/info?status=editing')
        }}
      >
        edit(push)
      </button>

      // 3๏ธโƒฃ ๋กœ์ปฌ ์ƒํƒœ๋„ ์œ ์ง€๋˜๊ณ , ๋ฐ์ดํ„ฐ ํŒจ์นญ๋„ ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค.
      <button
        onClick={() => {
          alert('edit')
          setClicked(true)
          router.push('/settings/my/info?status=editing', undefined, โบ๏ธ {
            shallow: true,
          })
        }}
      >
        edit(shallow)
      </button>

๋ฒ„ํŠผ 3๊ฐœ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ, ์ƒˆ๋กœ ๋ฆฌ๋ Œ๋”๊ฐ€ ๋˜๋ฉด์„œ ๋ฐ์ดํ„ฐ ํŒจ์น˜๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์ƒ๋‹จ ์ชฝ์— ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

export async function getServerSideProps() {
  console.log('server')
  return {
    props: {},
  }
}

getServerSideProps๋ฅผ ์ด์šฉํ•ด์„œ ํ„ฐ๋ฏธ๋„ ์ฝ˜์†”์— 'server' ๋ผ๋Š” ๋ฉ˜ํŠธ๊ฐ€ ์ฐํžˆ๋Š”์ง€ ํ™•์ธ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ shallow๋ฅผ ํ–ˆ์„ ๊ฒฝ์šฐ์—๋Š” ๋ฐ์ดํ„ฐ ํŒจ์นญ์ด ์•ˆ๋์ง€๋งŒ ๋กœ์ปฌ ์ƒํƒœ๋Š” ์œ ์ง€๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.


API๋ž€

  • ์ปดํ“จํ„ฐ๋‚˜ ์ปดํ“จํ„ฐ ํ”„๋กœ๊ทธ๋žจ ์‚ฌ์ด์˜ ์—ฐ๊ฒฐ
  • FE <=> BE ๊ฐ„์˜ ์—ฐ๊ฒฐ
  • ํ”„๋ก ํŠธ๋Š” ๊ณ ๊ฐ๊ณผ ๋‹ฟ์•„์žˆ๊ณ , ๋ฐฑ์—”๋“œ๋Š” DB์— ๋‹ฟ์•„์žˆ๋‹ค.
  • ์‹ค์ œ ์„œ๋น„์Šค ์˜ˆ์ œ) ์ปค๋จธ์Šค ์‚ฌ์ดํŠธ - ๊ฐœ๋ฐœ์ž๋„๊ตฌ F12 - ๋„คํŠธ์›Œํฌ ํƒญ ์—์„œ ํ™•์ธ ๊ฐ€๋Šฅ

Next ์—์„œ api ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

  • /pages/api/ํŒŒ์ผ๋ช….js

์ด์ฒ˜๋Ÿผ pages ๋””๋ ‰ํ† ๋ฆฌ ์•ˆ์—๋‹ค๊ฐ€ api ํด๋”๋ฅผ ๋งŒ๋“ค์–ด์„œ api๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

import { userDetail } from 'constants/userDetail'

export default function handler(req, res) {
  res.status(200).json(userDetail)
}

์ด๋Ÿฐ์‹์œผ๋กœ ๋ถˆ๋Ÿฌ์™€์„œ

  useEffect(() => {
    fetch('/api/user')
      .then((res) => res.json())
      .then((data) => {
        setName(data.name)
      })
  }, [])

์ด๋ ‡๊ฒŒ ํ˜ธ์ถœํ•ด์ฃผ๊ธฐ.

Dynamic API Routes

  • pages/api/user-info/[uid].js

๐Ÿ“ api/[uid].js ๋ผ๋Š” ํŒŒ์ผ๋ช…์— ์•„๋ž˜์™€ ๊ฐ™์ด ๋‹ค์ด๋‚˜๋ฏน api ๋ผ์šฐํŒ…

export default function handler(req, res) {
  const { uid } = req.query
  res.status(200).json({ name: `LeeHYUNJU ${uid}` })
}
  • Routing ์—์„œ ๋‹ค๋ค˜๋˜ ์—ฌ๋Ÿฌ Slug ํ™œ์šฉ๋ฒ• ์ ์šฉ ๊ฐ€๋Šฅ
  • ๋‹ค์ค‘ Route
/api/post/create.js
/api/post/[pid].js
/api/post/[...slug].js --> ๋‹ค์ค‘ slug
/api/post/[[...slug]].js --> ์˜ต์…”๋„ํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋‹ค.

๐Ÿช ์ฟ ํ‚ค ์ •๋ณด๋„ ๋‹ด์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

export default function handler(req, res) {
  const { uid } = req.query
  const cookies = req.cookies
  res.status(200).json({ name: `LeeHYUNJU ${uid} ${JSON.stringify(cookies)}` })
}

API ๋ฏธ๋“ค์›จ์–ด

  • ๋‚ด์žฅ ๋ฏธ๋“ค์›จ์–ด์˜ ๊ธฐ๋Šฅ

    • req.cookies / req.query ...
  • req/res ๊ด€๋ จ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ๋“ค์€ Middleware ๋“ค์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ex) CORS (๊ต์ฐจ ์ถœ์ฒ˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ )

Response

  • res.status(code)
  • res.json(body): serializable object
  • res.redirect(code, url) --> code๋Š” ์‚ฌ์šฉ์ž ์ฝ”๋“œ๋ฅผ ๋œปํ•œ๋‹ค.
  • res.send(body) : string / object / Buffer

About

๐Ÿ“š NextJS (๊ธฐ๋ณธ/์‹ฌํ™”) ๋‚ด์šฉ ์ •๋ฆฌ ~ing

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published