๐Ÿ’Ÿ
React์™€ Next.js ๋น„๊ต + ํŽ˜์ด์ง€ ๋ผ์šฐํ„ฐ ์ •๋ฆฌ
2025๋…„ 11์›” 30์ผ

Next.js์™€ React์˜ ์ฐจ์ด, Next.js์˜ Page Router์™€ App Rotuer์˜ ์ฐจ์ด์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค. ๊ณ„์† ์ฝ”๋“œ๋กœ๋งŒ ์ง์ ‘ ์งœ๋ดค์ง€, ๋จธ๋ฆฌ ์†์— ๊ฐœ๋… ์ •๋ฆฌ๋ฅผ ํ•ด๋ณด๊ณ ์ž ํฌ์ŠคํŒ…์„ ํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค!

React vs Next.js

๋จผ์ € React๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, Next.js๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋ผ๊ณ  ๊ฐ ๊ณต์‹ ์‚ฌ์ดํŠธ์— ์†Œ๊ฐœ๋ฅผ ํ•ด๋†จ๋‹ค.

๋ฆฌ์•กํŠธ ๊ณต์‹๋ฌธ์„œ Next.js ๊ณต์‹๋ฌธ์„œ

React๋Š” UI ๊ฐœ๋ฐœ์„ ์œ„ํ•œ JavaScript ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ Next.js๋Š” React ์ „์šฉ์˜ ์›น ๊ฐœ๋ฐœ ํ”„๋ ˆ์ž„์›Œํฌ

๊ทธ๋Ÿผ ์—ฌ๊ธฐ์„œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ฐจ์ด๋Š” ๋ฌด์—‡์ผ๊นŒ?

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

๊ธฐ๋Šฅ ๊ตฌํ˜„์˜ ์ฃผ๋„๊ถŒ์ด ๋ˆ„๊ตฌ์—๊ฒŒ ์žˆ๋Š”๊ฐ€?

์ฃผ๋„๊ถŒ์ด ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์žˆ๋‹ค๋ฉด? ๐Ÿ‘‰๐Ÿป ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ฃผ๋„๊ถŒ์ด ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์—†๋‹ค๋ฉด? ๐Ÿ‘‰๐Ÿป ํ”„๋ ˆ์ž„์›Œํฌ

์ฃผ๋„๊ถŒ์„ ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐ€์ง„๋‹ค๋ฉด, ๊ธฐ๋Šฅ ๊ตฌํ˜„์„ ์›ํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋งŒ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๊ณ  ์“ฐ๊ณ  ์‹ถ์€ ๋„๊ตฌ์™€ ๊ธฐ์ˆ ์„ ๋งˆ์Œ๋Œ€๋กœ ์“ธ ์ˆ˜ ์žˆ๋‹ค. => ์ž์œ ๋„โฌ†๏ธ, ๋Œ€์‹  ๊ฐœ๋ฐœ์ž๊ฐ€ ๋‹ค ๊ตฌํ˜„ํ•ด์•ผ ํ•จ..

๋ฐ˜๋Œ€๋กœ ์ฃผ๋„๊ถŒ์„ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๊ฐ€์ง„๋‹ค๋ฉด, ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ด์šฉํ•˜๊ณ  ํ—ˆ์šฉํ•˜๋Š” ๋ฒ”์œ„ ๋‚ด์—์„œ๋งŒ ์ถ”๊ฐ€ ๋„๊ตฌ๋ฅผ ๊ฐ€์ ธ๊ฐ€ ์“ธ ์ˆ˜ ์žˆ๋‹ค. => ์ž์œ ๋„โฌ‡๏ธ, ๋Œ€์‹  ๋ณต์žกํ•œ ๊ธฐ๋Šฅ๋“ค์„ ์ œ๊ณตํ•ด์ฃผ๊ธฐ์— ๊ฐ€์ ธ๋‹ค ์“ฐ๋ฉด ๋œ๋‹ค!

CSR vs SSR

๋‹ค๋ฅธ ์ฐจ์ด์ ์œผ๋กœ๋Š” React๋Š” CSR(Client Side Rendering)์„, Next.js๋Š” SSR(Server Side Rendering)์ด๋ผ๋Š” ํŠน์ง•์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

์ด๋Š” ํฌ๊ฒŒ ์‚ฌ์ „ ๋ Œ๋”๋ง์„ ํ•˜๋А๋ƒ, ์•ˆํ•˜๋А๋ƒ์˜ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

์‚ฌ์ „ ๋ Œ๋”๋ง์ด๋ž€, ๋ธŒ๋ผ์šฐ์ €์˜ ์š”์ฒญ์— ์‚ฌ์ „์— ๋ Œ๋”๋ง์ด ์™„๋ฃŒ๋œ HTML์„ ์‘๋‹ตํ•˜๋Š” ๋ Œ๋”๋ง ๋ฐฉ์‹์ด๋‹ค. CSR์˜ ๋‹จ์ ์„ ํšจ์œจ์ ์œผ๋กœ ํ•ด๊ฒฐํ•˜๋Š” ๊ธฐ์ˆ ์ด๋‹ค!

๊ทธ๋ ‡๋‹ค๋ฉด CSR์€ ๋ฌด์—‡์ผ๊นŒ?

CSR(Client Side Rendering)

React.js ์•ฑ์˜ ๊ธฐ๋ณธ์ ์ธ ๋ Œ๋”๋ง ๋ฐฉ์‹์ด๋‹ค. ํด๋ผ์ด์–ธํŠธ(๋ธŒ๋ผ์šฐ์ €)์—์„œ ์ง์ ‘ ํ™”๋ฉด์„ ๋ Œ๋”๋งํ•œ๋‹ค.

CSR ์ด๋ฏธ์ง€ ์ถœ์ฒ˜: ํ•œ ์ž… ํฌ๊ธฐ๋กœ ์ž˜๋ผ๋จน๋Š” Next.js

  1. ์œ ์ €๊ฐ€ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ†ตํ•ด ์ดˆ๊ธฐ ์ ‘์† ์š”์ฒญ์„ ์„œ๋ฒ„์— ๋ณด๋‚ด๊ณ , ๋ฆฌ์•กํŠธ ์›น์„œ๋ฒ„๋Š” ๋นˆ๊ป๋ฐ๊ธฐ์ธ index.html ํŒŒ์ผ์„ ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ์ „์†กํ•œ๋‹ค.
  2. ๋ธŒ๋ผ์šฐ์ €๋Š” ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ html ํŒŒ์ผ์„ ํ™”๋ฉด์— ๋ Œ๋”๋งํ•œ๋‹ค.
  3. ์ด๋•Œ, ์‚ฌ์šฉ์ž๋Š” ํฐํ™”๋ฉด์„ ๋ณด๊ฒŒ ๋œ๋‹ค.
  4. ์„œ๋ฒ„๋Š” ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ JS ํŒŒ์ผ๋“ค์„ ๋ฒˆ๋“ค๋งํ•˜๊ณ  ์ด ๋ฒˆ๋“ค๋งํ•œ ๊ฒƒ์„ ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ๋ณด๋‚ธ๋‹ค.
  5. ๋ธŒ๋ผ์šฐ์ €๋Š” ์ด ๋ฒˆ๋“ค๋ง๋œ JS๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์ด๋•Œ, ๋ฆฌ์•กํŠธ ์•ฑ์ด ๊ตฌ๋™๋˜์–ด ์‹ค์ œ ํ™”๋ฉด์— ๋‚˜ํƒ€๋‚˜๊ฒŒ ๋œ๋‹ค.
  6. ๊ฒฐ๊ณผ์ ์œผ๋กœ ์‚ฌ์šฉ์ž๋Š” ์š”์ฒญํ•œ ์›นํŽ˜์ด์ง€๋ฅผ ๋ณผ ์ˆ˜๊ฐ€ ์žˆ๊ฒŒ ๋œ๋‹ค.

CSR์€ ์ด๋ ‡๋“ฏ ์ดˆ๊ธฐ ๋กœ๋“œ์—๋Š” ํฐํ™”๋ฉด์ด ๋‚˜์˜จ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์žฅ์ ์œผ๋กœ, ํŽ˜์ด์ง€ ์ด๋™์ด ๋งค์šฐ ๋น ๋ฅด๊ณ  ์พŒ์ ํ•˜๋‹ค๋Š” ํŠน์ง•์ด ์žˆ๋‹ค.

์™œ ๊ทธ๋Ÿด๊นŒ?๐Ÿค”

์ด๋Š” ์„œ๋ฒ„๊ฐ€ JS ๋ฒˆ๋“ค๋ง์„ ํ•˜๊ณ  ๋‚œ ํ›„, ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ์ „์†กํ–ˆ์„ ๋•Œ ๋ฒˆ๋“ค๋ง๋œ JS ํŒŒ์ผ์—๋Š” ๋ฆฌ์•กํŠธ ์ฝ”๋“œ๋“ค์ด ๋“ค์–ด์žˆ๊ณ  ์ฆ‰, ํ•ด๋‹น ์„œ๋น„์Šค์˜ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ๋“ค์ด ๋“ค์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์ดํ›„ ์‚ฌ์šฉ์ž๊ฐ€ ๋‹ค๋ฅธ ํŽ˜์ด์ง€์— ์ ‘์†ํ•˜๋”๋ผ๋„, ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ž์ฒด์ ์œผ๋กœ ๋ฆฌ์•กํŠธ ์•ฑ์„ ์‹คํ–‰ํ•ด์„œ ๋น ๋ฅธ ์†๋„๋กœ ํŽ˜์ด์ง€ ์ด๋™์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋œ๋‹ค!

ํ•˜์ง€๋งŒ ์•ž์„œ ๋งํ–ˆ๋“ฏ์ด FCP(์š”์ฒญ ์‹œ์ž‘ ์‹œ์ ๋ถ€ํ„ฐ ์ปจํ…์ธ ๊ฐ€ ์ฒ˜์Œ ๋‚˜ํƒ€๋‚˜๋Š”๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„) ๊ฐ€ ๊ธธ์–ด์ ธ ์ดˆ๊ธฐ ์ ‘์† ์‹œ๊ฐ„์ด ๊ธธ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

SSR(Server Side Rendering)

SSR์€ ์•ž์„œ ๋งํ•œ ์‚ฌ์ „ ๋ Œ๋”๋ง์œผ๋กœ CSR์˜ ๋‹จ์ ์„ ์ด๊ฒจ๋‚ธ๋‹ค.

  1. ์œ ์ €๊ฐ€ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„์—๊ฒŒ ์ดˆ๊ธฐ ์ ‘์† ์š”์ฒญ์„ ํ•œ๋‹ค.
  2. ์„œ๋ฒ„๋Š” ์ง์ ‘ JS ์ฝ”๋“œ(๋ฆฌ์•กํŠธ ์ฝ”๋“œ)๋ฅผ ์‹คํ–‰ํ•ด์„œ ๋ชจ๋“  ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋“ค์„ html๋กœ ๋ณ€ํ™˜(์‚ฌ์ „ ๋ Œ๋”๋ง)์„ ํ•œ๋‹ค.
  3. ๋ Œ๋”๋ง์ด ์™„๋ฃŒ๋œ ํ›„, html ํŒŒ์ผ์„ ๊ทธ๋Œ€๋กœ ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ์ „์†กํ•œ๋‹ค.
  4. ๋ธŒ๋ผ์šฐ์ €๋Š” ์ „์†ก ๋ฐ›์€ html ํŒŒ์ผ์„ ํ™”๋ฉด์— ๊ทธ๋Œ€๋กœ ๋ Œ๋”๋งํ•œ๋‹ค.
  5. ๊ฒฐ๊ณผ์ ์œผ๋กœ ์‚ฌ์šฉ์ž๋Š” ์š”์ฒญํ•œ ์›นํŽ˜์ด์ง€๋ฅผ ๋ณผ ์ˆ˜๊ฐ€ ์žˆ๊ฒŒ ๋œ๋‹ค.

์ •๋ฆฌํ•˜์ž๋ฉด, ์„œ๋ฒ„์—์„œ ๋ฐ”๋กœ js๋ฅผ ์‹คํ–‰ํ•ด์„œ html ํ™”๋ฉด์„ ๊ทธ๋ ค๋‚ธ ์ƒํƒœ๋กœ ๋ธŒ๋ผ์šฐ์ €์— ๋ณด๋‚ธ๋‹ค๋Š” ๋œป!! => FCP ๊ฐ์†Œ

Hydration(์ˆ˜ํ™”)

๋ธŒ๋ผ์šฐ์ €๋Š” ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ html์„ ๋ฐ›๊ณ  ์‚ฌ์šฉ์ž์—๊ฒŒ ๋„˜๊ฒจ์ค€ ํ›„ ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์ดํŠธ์— ํด๋ฆญ์„ ์‹œ๋„ํ•˜๋ฉด ์ž‘๋™์„ ํ•˜์ง€ ์•Š๊ฒŒ ๋œ๋‹คโ€ฆ ์™œ๊ทธ๋Ÿด๊นŒ?

์ด๋Š” ๋ธŒ๋ผ์šฐ์ €๊ฐ€ js ํŒŒ์ผ์„ ๊ฐ–๊ณ  ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ดํ›„ ์„œ๋ฒ„๋Š” JS ๋ฒˆ๋“ค๋ง ํŒŒ์ผ์„ ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ์ „์†กํ•˜๊ณ , ๊ทธ์ œ์„œ์•ผ ๋ธŒ๋ผ์šฐ์ €๋Š” html๊ณผ JS๋ฅผ ์—ฐ๊ฒฐ์‹œ์ผœ ์‹คํ–‰ํ•œ๋‹ค. ์ดํ›„, ์‚ฌ์šฉ์ž๋Š” ์ƒํ˜ธ์ž‘์šฉ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋œ๋‹ค!!

์ด๋ ‡๊ฒŒ html๊ณผ js๋ฅผ ์—ฐ๊ฒฐ์‹œํ‚ค๋Š” ๊ณผ์ •์„ Hydration ๊ณผ์ •์ด๋ผ๊ณ  ํ•œ๋‹ค.

SSR ์ด๋ฏธ์ง€ ์ถœ์ฒ˜: ํ•œ ์ž… ํฌ๊ธฐ๋กœ ์ž˜๋ผ๋จน๋Š” Next.js

๊ทธ๋ ‡๊ธฐ์— SSR์€ ์ดˆ๊ธฐ ๋กœ๋“œ ์†๋„๊ฐ€ ๋น ๋ฅด๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. ๋˜ํ•œ, ์ดํ›„ ํŽ˜์ด์ง€ ์ด๋™ ์†๋„๋„ ์ด๋ฏธ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ JS ๋ฒˆ๋“ค๋ง ํŒŒ์ผ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— CSR๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ SSR์˜ ์‚ฌ์ „ ๋ Œ๋”๋ง ๋ฐฉ์‹์€ ๋น ๋ฅธ FCP ๋‹ฌ์„ฑ(CSR์˜ ๋‹จ์  ํ•ด์†Œ) + ๋น ๋ฅธ ํŽ˜์ด์ง€ ์ด๋™(CSR์˜ ์žฅ์  ์Šน๊ณ„) ์˜ ํŠน์ง•์„ ๊ฐ–๊ฒŒ ๋œ๋‹ค. ๐Ÿฅณ๐ŸŽ‰


Page Router

ํ˜„์žฌ ๋งŽ์€ ๊ธฐ์—…์—์„œ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋Š” ์•ˆ์ •์ ์ธ ๋ผ์šฐํ„ฐ

Page Router๋Š” pages ํด๋”์˜ ๊ตฌ์กฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํŽ˜์ด์ง€ ๋ผ์šฐํŒ…์„ ์ œ๊ณตํ•œ๋‹ค.

ํŒŒ์ผ๋ช… ๋˜๋Š” ํด๋”๋ช… ๊ธฐ๋ฐ˜์˜ ๋ผ์šฐํŒ…์„ ๊ฐ€์ง„๋‹ค.

alt text

๋™์  ๋ผ์šฐํŒ…์€ ๋Œ€๊ด„ํ˜ธ๋กœ ๋™์  ํŒŒ์ผ๋ช…์„ ๋งŒ๋“ค์–ด์ฃผ๋ฉด ๋œ๋‹ค.

alt text

_app.tsx์™€ _docupent.tsx์˜ ์—ญํ• 

pages ํด๋” ์•ˆ์— ์žˆ๋Š” ์ด ๋‘ ํŒŒ์ผ์€ ํŽ˜์ด์ง€์˜ ์—ญํ• ์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค. next ํ”„๋กœ์ ํŠธ์˜ ๋ชจ๋“  ํŽ˜์ด์ง€์— ์ ์šฉํ•  ๊ณตํ†ต๋œ ๋กœ์ง์ด๋‚˜ ๋ ˆ์ด์•„์›ƒ, ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•ด ํ•„์š”ํ•œ ํŒŒ์ผ๋“ค์ด๋‹ค.

_app.tsx

React์—์„œ์˜ App ์ปดํฌ๋„ŒํŠธ์™€ ๊ฐ™์€ ๊ฐœ๋…์ด๋‹ค. ์ฆ‰, ๋ฃจํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค. ์—ฌ๊ธฐ์„œ ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ๊ณผ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

_docupent.tsx

๋ชจ๋“  ํŽ˜์ด์ง€์— ๊ณตํ†ต์œผ๋กœ ์ ์šฉ๋˜์–ด์•ผ ํ•˜๋Š” next ์•ฑ์˜ html ์ฝ”๋“œ๋ฅผ ์„ค์ •ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์ด๋‹ค. React ์•ฑ์˜ index.html๊ณผ ๊ฐ™์€ ๊ฐœ๋…์ด๋‹ค. ์—ฌ๊ธฐ์„œ ๋ฉ”ํƒ€ ํƒœ๊ทธ๋‚˜ ํฐํŠธ, ์„œ๋“œํŒŒํ‹ฐ script ๋“ฑ์„ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค.

์ค‘์ฒฉ ๋ผ์šฐํ„ฐ

์ค‘์ฒฉ ๋ผ์šฐํŒ…์„ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ํด๋”๋ช… ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ… ๋ฐฉ์‹์—์„œ ์›ํ•˜๋Š” ํŒŒ์ผ๋ช…์˜ ์ƒˆ ํŒŒ์ผ์„ ๋งŒ๋“ค๋ฉด ๊ทธ ํŒŒ์ผ๋ช…์ด ์ค‘์ฒฉ ๋ผ์šฐํŒ…์ด ๋œ๋‹ค.(๋‹น์—ฐํžˆ ์ด๋•Œ ํŒŒ์ผ๋ช…์ด ์•„๋‹Œ ํด๋”๋ช… ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒˆ ํด๋”๋ฅผ ๋งŒ๋“ค๊ณ  index.tsx๋ฅผ ๋งŒ๋“ค์–ด๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.)

useRouter

๋ณดํ†ต ์›ํ•˜๋Š” ๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅํ•  ๋•Œ ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์ด๋ผ๋Š” ํ˜•ํƒœ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์ „๋‹ฌ๋˜๋Š”๋ฐ ์ด ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์˜ ๊ฐ’์„ ๊บผ๋‚ด์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด next/router์˜ useRouter๋ฅผ ํ™œ์šฉํ•œ๋‹ค.

๊ทผ๋ฐ? next/router์™€ next/navigation์ด ์žˆ๋‹ค. ๋‘˜์˜ ์ฐจ์ด๋Š” ๋ญ˜๊นŒ?๐Ÿค”

next/navigation์€ App router์—์„œ ์‚ฌ์šฉ๋˜๋Š” ํŒจํ‚ค์ง€๋‹ค. useSearchParams๋ฅผ ํ™œ์šฉํ•œ๋‹ค. Page ๋ผ์šฐํ„ฐ์—์„œ๋Š” next/router์˜ useRouter๋กœ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ์œผ๋‹ˆ ๋‘˜์˜ ์ฐจ์ด๋ฅผ ์žŠ์ง€ ๋ง์ž.

useRouter() ๋ฅผ ์ฝ˜์†”๋กœ ์ฐ์–ด๋ณด๋ฉด ๋‹ค์Œ์ฒ˜๋Ÿผ ๋‚˜์˜จ๋‹ค. alt text

์œ„ ์‚ฌ์ง„์„ ๋ณด๋ฉด ํ•œ ์ฝ˜์†”์— ๊ต‰์žฅํžˆ ๋งŽ์€ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์ฐํžŒ ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. back๊ณผ push์ฒ˜๋Ÿผ ๋‹ค๋ฅธ ๊ฒฝ๋กœ๋กœ ์ด๋™ํ•˜๋Š” ๋ฉ”์„œ๋“œ, ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์„ ๋ฐ›์•„์˜ค๋Š” query ๋“ฑ์ด ๋“ค์–ด์žˆ๋‹ค.

๊ทผ๋ฐ ์™œ ์ฝ˜์†”์ด ๋‘ ๋ฒˆ ์ฐํ˜”๋Š”๊ฐ€? ์ž์„ธํžˆ ๋ณด๋ฉด query์— ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค. next ์•ฑ์ด ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง์„ ์ฝ์œผ๋ฉด์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•œ ๋ฒˆ ๋” ๋ Œ๋”๋งํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋™์  ๋ผ์šฐํŒ…

ํŒŒ์ผ๋ช…์— ๋Œ€๊ด„ํ˜ธ๋กœ ๊ฐ์‹ธ๋ฉด, ์ด๋Š” ๋™์  ๋ผ์šฐํŒ…์„ ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ๋ณดํ†ต id, slug ๋“ฑ์œผ๋กœ ๋งŽ์ด ์“ด๋‹ค.

pages/book/[id].tsx๋กœ ํŒŒ์ผ์„ ๋งŒ๋“ค๋ฉด, /book/{id} ํ˜•ํƒœ๋กœ ํŽ˜์ด์ง€๊ฐ€ ๋™์ ์œผ๋กœ ๋งŒ๋“ค์–ด์ง„๋‹ค.

์—ฌ๊ธฐ์„œ ๋งŒ์•ฝ /book/{id}/{id2}/{di3} ์ด๋Ÿฐ ์‹์˜ ๋’ค์— ๋ผ์šฐํŒ…์ด ๋” ๋ถ™์œผ๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

์—†๋Š” ํŽ˜์ด์ง€๋กœ ๋œฌ๋‹ค.(404)

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„ , Catch-all Segments๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

Catch-all Segments

[id].tsx๋ฅผ [โ€ฆid].tsx๋กœ ๋ฐ”๊ฟ”๋ณด์ž.

pages/shop/[...slug].js๋Š” /shop/clothes์™€ /shop/clothes/tops, /shop/clothes/tops/t-shirts ๋ชจ๋‘ ํฌํ•จํ•œ๋‹ค.

Catch-all Segments

๊ทผ๋ฐ ์—ฌ๊ธฐ์„œ /shop ๊ฒฝ๋กœ๋กœ ๋“ค์–ด๊ฐ€๋ฉด, 404 ํŽ˜์ด์ง€๊ฐ€ ๋œฌ๋‹ค. ๋งŒ์•ฝ ๋’ค์— ์ถ”๊ฐ€ ๊ฒฝ๋กœ๊ฐ€ ๋ถ™๋“  ์•ˆ๋ถ™๋“  ์กฐ๊ฑด ์—†์ด ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด [[...slug]].tsx์ฒ˜๋Ÿผ ๋Œ€๊ด„ํ˜ธ๋กœ ํ•œ ๋ฒˆ ๋” ๊ฐ์‹ธ์ฃผ๋ฉด ๋œ๋‹ค.

Pre-Fetching

์‚ฌ์šฉ์ž๊ฐ€ ํ˜„์žฌ ๋ณด๊ณ  ์žˆ๋Š” ํŽ˜์ด์ง€์—์„œ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „์— ๋ฏธ๋ฆฌ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

๊ทผ๋ฐ ๋ถ„๋ช… Next.js๋Š” html์„ ์‚ฌ์ „ ๋ Œ๋”๋ง ํ•˜๊ณ  ์ดํ›„ ์„œ๋ฒ„๊ฐ€ js ๋ฒˆ๋“ค๋ง ๋œ๊ฑธ ๋ณด๋‚ด์„œ ํŽ˜์ด์ง€ ์ด๋™ ์‹œ์— CSR ๋ฐฉ์‹์œผ๋กœ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ js๋ฅผ ์‹คํ–‰ํ•ด์„œ ๋น ๋ฅด๊ฒŒ ์ด๋™๋œ๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ Pre-Fetching์€ ์™œ ํ•„์š”ํ•œ๊ฑธ๊นŒ?๐Ÿค”

Next.js๋Š” js ํŒŒ์ผ๋“ค์„ ํŽ˜์ด์ง€๋ณ„๋กœ ๋ฏธ๋ฆฌ ์Šคํ”Œ๋ฆฌํŒ…ํ•ด์„œ ์ €์žฅ์„ ํ•ด๋‘”๋‹ค. ์ฆ‰, ์งˆ๋ฌธ์—์„œ ๋งํ•œ ์„œ๋ฒ„๊ฐ€ js ๋ฒˆ๋“ค๋ง ๋œ ๊ฑธ ๋ณด๋‚ธ๋‹ค๋Š” ๊ฒƒ์€ ํ•ด๋‹น ํŽ˜์ด์ง€์˜ ์Šคํ”Œ๋ฆฌํŒ…๋œ ๋ฒˆ๋“ค๋ง ํŒŒ์ผ์ด๋ผ๋Š” ๊ฒƒ์ด๋‹ค!

๋งŒ์•ฝ ์ด๋ ‡๊ฒŒ ํ•˜์ง€ ์•Š๊ณ  ๋ชจ๋“  ํŽ˜์ด์ง€์˜ js ํŒŒ์ผ์„ ๋˜์ ธ์ฃผ๊ฒŒ ๋˜๋ฉด, ์šฉ๋Ÿ‰์ด ์ปค์ง€๊ณ  ํ•˜์ด๋“œ๋ ˆ์ด์…˜์ด ๋Šฆ์–ด์ง„๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ๊ฐ„(TTI)์ด ๋Šฆ์–ด์ง€๊ฒŒ ๋œ๋‹ค.

์ดํ›„, ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๊ฒŒ ๋  ๋•Œ ํ•ด๋‹น ํŽ˜์ด์ง€๊ฐ€ ํ•„์š”๋กœ ํ•˜๋Š” js ๋ฒˆ๋“ค๋ง์„ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋˜ ๋ฐ›์•„์™€์•ผ ํ•˜๋Š”๋ฐ ์ด๋Ÿฐ ๊ฒฝ์šฐ, ํ•˜์ด๋“œ๋ ˆ์ด์…˜ ๋ฉด์—์„œ๋Š” ์ข‹์„์ง€๋ผ๋„ ํŽ˜์ด์ง€ ์ด๋™์€ ๋А๋ ค์ง€๊ณ  ๋น„ํšจ์œจ์ ์ด๊ฒŒ ๋œ๋‹ค.

์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Pre-Fetchig์ด ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

ํ”„๋ฆฌํŒจ์นญ์€ ์ดˆ๊ธฐ ์ ‘์†์ด ๋๋‚œ ํ›„, ๋‹ค์Œ ํŽ˜์ด์ง€ ์ด๋™์ด ์ด๋ฃจ์–ด์ง€๊ธฐ ์ „์— ์—ฐ๊ฒฐ๋œ ๋ชจ๋“  ํŽ˜์ด์ง€์˜ Js ๋ฒˆ๋“ค ํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์˜ค๊ฒŒ ๋œ๋‹ค.

alt text

์ฐธ๊ณ ๋กœ ํ”„๋ฆฌํŒจ์นญ์€ dev ๋ชจ๋“œ์—์„œ๋Š” ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค. production ๋ชจ๋“œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค! ๊ทธ๋Ÿฌ๋‹ˆ ๋นŒ๋“œํ•˜๊ณ  ์šด์˜ ํ™˜๊ฒฝ์—์„œ ํ™•์ธํ•ด๋ณด์ž.

alt text

dev ๋ชจ๋“œ์ผ ๋•Œ ๋„คํŠธ์›Œํฌ ํƒญ์ด๋‹ค. search์™€ book ํŽ˜์ด์ง€์˜ js ํŒŒ์ผ๋“ค์ด ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค.

alt text

prod ๋ชจ๋“œ์ผ ๋•Œ ๋„คํŠธ์›Œํฌ ํƒญ์ด๋‹ค. search์™€ book ํŽ˜์ด์ง€์˜ js ํŒŒ์ผ๋“ค์ด ๋ณด์ด๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค. ํ”„๋ฆฌํŒจ์นญ์ด ์ œ๋Œ€๋กœ ์ด๋ฃจ์–ด์ง„ ๊ฒƒ์ด๋‹ค.

์—ฌ๊ธฐ์„œ ๋˜ ํ•˜๋‚˜์˜ ๋ฌธ์ œ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ํ˜„์žฌ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

export default function App({ Component, pageProps }: AppProps) {
  const router = useRouter();

  const onClickButton = () => {
    router.push("/test");
  };

  return (
    <>
      <header>
        <Link href="/">ํ™ˆ</Link>
        &nbsp;
        <Link href="/search">๊ฒ€์ƒ‰</Link>
        &nbsp;
        <Link href="/book/1">์ฑ… 1</Link>
        <div>
          <button onClick={onClickButton}>/test ํŽ˜์ด์ง€๋กœ ์ด๋™</button>
        </div>
      </header>
      <Component {...pageProps} />
    </>
  );
}

์—ฌ๊ธฐ์„œ Link๋กœ ๊ฐ์‹ธ์ง„ ํŽ˜์ด์ง•์— ๋Œ€ํ•ด์„œ๋Š” ํ”„๋ฆฌํŒจ์นญ์ด ์ž˜ ์ด๋ฃจ์–ด์ง€๋Š”๋ฐ, /test ํŽ˜์ด์ง€์— ๋Œ€ํ•ด์„œ๋Š” ํ”„๋ฆฌํŒจ์นญ์ด ์ด๋ฃจ์–ด์ง€์ง€ ์•Š๋Š”๋‹ค. ์ฆ‰, /test๋กœ ํŽ˜์ด์ง€ ์ด๋™ ์‹œ, test js ํŒŒ์ผ์ด ์ƒˆ๋กœ ๋„คํŠธ์›Œํฌ ํƒญ์— ๋ถˆ๋Ÿฌ์™€์ง„๋‹ค.

router.push ํŽ˜์ด์ง• ์ฒ˜๋ฆฌํ•œ ๊ฒƒ๋„ ํ”„๋ฆฌํŒจ์นญ์ด ๋˜๊ฒŒ ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ?

App ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ๋˜์—ˆ์„ ๋•Œ(์ฒ˜์Œ ํ™”๋ฉด์— ๊ทธ๋ ค์กŒ์„ ๋•Œ) ํ”„๋ฆฌํŒจ์น˜ ํ•˜๋„๋ก ํ•˜๋ฉด ๋œ๋‹ค.

์ฝ”๋“œ๋Š” ๋‹ค์Œ ๊ฑธ ๋กœ์ง์— ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.

useEffect(() => {
  router.prefetch('/test');
}, [])

๋ฐ˜๋Œ€๋กœ Link ํƒœ๊ทธ์˜ prefetch๋ฅผ ํ•ด์ œํ•˜๊ณ  ์‹ถ์€๋ฉด?

prefetch={false} ์†์„ฑ์„ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

alt text

test js์˜ ํ”„๋ฆฌํŒจ์นญ, search js์˜ ํ”„๋ฆฌํŒจ์นญ ํ•ด์ œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค!

API Routes

Next.js์—์„œ API๋ฅผ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ

/pages/api ํด๋” ์•ˆ์— ํŒŒ์ผ์„ ๋งŒ๋“ค๋ฉด, ๊ทธ ํŒŒ์ผ ๊ฒฝ๋กœ = API ์—”๋“œํฌ์ธํŠธ๊ฐ€ ๋œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด

  • pages/api/hello.ts โ†’ GET /api/hello
  • pages/api/user/index.ts โ†’ GET /api/user
  • pages/api/user/[id].ts โ†’ GET /api/user/123 ์ด๋Ÿฐ ์‹์œผ๋กœ ๋™์  ๋ผ์šฐํŒ…๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

๊ธฐ๋ณธ ํ˜•ํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค:

// pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next';

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  // ์š”์ฒญ ๋ฉ”์„œ๋“œ์— ๋”ฐ๋ผ ๋ถ„๊ธฐ
  if (req.method === 'GET') {
    return res.status(200).json({ message: 'Hello API' });
  }

  // ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š” ๋ฉ”์„œ๋“œ ์ฒ˜๋ฆฌ
  res.setHeader('Allow', ['GET']);
  return res.status(405).end('Method Not Allowed');
}

CSS Module ๋ฐฉ์‹์ด๋ž€?

ํŽ˜์ด์ง€ ๋ณ„๋กœ ํด๋ž˜์Šค ๋„ค์ž„์ด ๊ฒน์ณ์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ(์Šคํƒ€์ผ ์ถฉ๋Œ)๋ฅผ ์ž๋™์œผ๋กœ ์œ ๋‹ˆํฌํ•œ ํด๋ž˜์Šค ๋„ค์ž„์œผ๋กœ ๋ณ€ํ™˜ํ•ด์คŒ์œผ๋กœ์จ ํ•ด๊ฒฐํ•œ ๋ฐฉ์‹์ด๋‹ค.

SSR, SSG, ISR

Next.js๋Š” ์„ธ ๊ฐ€์ง€์˜ ์‚ฌ์ „ ๋ Œ๋”๋ง ๋ฐฉ์‹์ด ์žˆ๋‹ค.

SSR(Server Side Rendering)

  • ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ์‚ฌ์ „ ๋ Œ๋”๋ง ๋ฐฉ์‹
  • ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ๋งˆ๋‹ค ์‚ฌ์ „ ๋ Œ์ €๋ง์„ ์ง„ํ–‰

SSR์€ ํŽ˜์ด์ง€ ๋‚ด๋ถ€์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ•ญ์ƒ ์ตœ์‹ ์œผ๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์ง€๋งŒ, ๋ฐ์ดํ„ฐ ์š”์ฒญ์ด ๋Šฆ์–ด์งˆ ๊ฒฝ์šฐ ๋ชจ๋“  ๊ฒŒ ๋Šฆ์–ด์ง„๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

export const getServerSideProps = async (
  context: GetServerSidePropsContext
) => {
  const id = context.params!.id;
  const book = await fetchOneBook(Number(id));

  return {
    props: { book },
  };
};

SSG(Static Site Generation)

  • SSR์˜ ๋‹จ์ ์„ ํ•ด๊ฒฐํ•˜๋Š” ์‚ฌ์ „ ๋ Œ๋”๋ง ๋ฐฉ์‹
  • ๋นŒ๋“œ ํƒ€์ž„์— ํŽ˜์ด์ง€๋ฅผ ๋ฏธ๋ฆฌ ์‚ฌ์ „ ๋ Œ๋”๋ง ํ•ด ๋‘ 

SSG ๋ฐฉ์‹์€ ์‚ฌ์ „ ๋ Œ๋”๋ง์— ๋งŽ์€ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜๋”๋ผ๋„ ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์—๋Š” ๋งค์šฐ ๋น ๋ฅธ ์†๋„๋กœ ์‘๋‹ตํ•œ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ, ๋งค๋ฒˆ ๋˜‘๊ฐ™์€ ํŽ˜์ด์ง€๋งŒ ์‘๋‹ตํ•˜๊ธฐ์— ์ตœ์‹  ๋ฐ์ดํ„ฐ ๋ฐ˜์˜์€ ์–ด๋ ต๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

์ œ๋Œ€๋กœ๋œ SSG ๋™์ž‘์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๊ผญ ์šด์˜ ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด์ž!

export const getStaticProps = async () => {
  const [allBooks, recoBooks] = await Promise.all([
    fetchBooks(),
    fetchRandomBooks(),
  ]);

  return {
    props: {
      allBooks,
      recoBooks,
    },
  };
};

๋งŒ์•ฝ ๋™์  ๊ฒฝ๋กœ๋ฅผ ๊ฐ€์ง„ ํŒŒ์ผ์„ SSG๋กœ ๋ถˆ๋Ÿฌ์˜จ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ณ๊นŒ? ์œ„์ฒ˜๋Ÿผ getStaticProps๋ฅผ ์ด์šฉํ•ด์„œ ์‹คํ–‰์„ ํ•ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์—๋Ÿฌ๊ฐ€ ๋‚œ๋‹ค.

alt text

๋นŒ๋“œํƒ€์ž„์— ์‚ฌ์ „๋ Œ๋”๋ง์„ ์ง„ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋–ค ๊ฒฝ๋กœ๋“ค์ด ์กด์žฌํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ•˜๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•œ ๊ฒƒ์ด๋‹ค.

์ด ์„ค์ •ํ•˜๋Š” ์—ญํ• ์„ ํ•จ์ˆ˜๊ฐ€ ๋ฐ”๋กœ getStaticPaths์ด๋‹ค.

export const getStaticPaths = () => {
  return {
    paths: [
      { params: { id: "1" } },
      { params: { id: "2" } },
      { params: { id: "3" } },
    ],
    fallback: true,
    // false - 404 NotFound
    // blocking - SSR ๋ฐฉ์‹
    // true - SSR ๋ฐฉ์‹ + ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ํด๋ฐฑ ์ƒํƒœ์˜ ํŽ˜์ด์ง€๋ถ€ํ„ฐ ๋ฐ˜ํ™˜
  };
};

export const getStaticProps = async (context: GetStaticPropsContext) => {
  const id = context.params!.id;
  const book = await fetchOneBook(Number(id));

  return {
    props: { book },
  };
};

์—ฌ๊ธฐ์„œ fallback ์˜ต์…˜์€ ๋ฌด์—‡์ผ๊นŒ?

fallback์€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ๋กœ๋กœ ๋“ค์–ด๊ฐ”์„ ๋•Œ ์–ด๋–ป๊ฒŒ ๋Œ€์ฒดํ•  ์ง€ ์„ค์ •ํ•˜๋Š” ์˜ต์…˜์ด๋‹ค.

false์ผ ๋•Œ๋Š” 404 NotFound๋ฅผ,
true์ผ ๋•Œ๋Š” SSR ๋ฐฉ์‹์œผ๋กœ ์—…๋ฐ์ดํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋˜, ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐ˜์‘์„ ๋น ๋ฅด๊ฒŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ํด๋ฐฑ ์ƒํƒœ ํŽ˜์ด์ง€๋ถ€ํ„ฐ ๋ฐ˜ํ™˜,
blocking์€ SSR ๋ฐฉ์‹์œผ๋กœ ์—…๋ฐ์ดํŠธ๋งŒ ์ง„ํ–‰ํ•˜๋Š” ์˜ต์…˜์ด๋‹ค.

ISR(Static Site Generation)

SSG ๋ฐฉ์‹์œผ๋กœ ์ƒ์„ฑ๋œ ์ •์  ํŽ˜์ด์ง€๋ฅผ ์ผ์ • ์‹œ๊ฐ„์„ ์ฃผ๊ธฐ๋กœ ๋‹ค์‹œ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

์ฆ‰, ๋น ๋ฅธ ์‘๋‹ต์„ ํ•ด์ฃผ๋Š” SSG์˜ ์žฅ์ ๊ณผ ์ตœ์‹  ๋ฐ์ดํ„ฐ ๋ฐ˜์˜์ด ๊ฐ€๋Šฅํ•œ SSR์˜ ์žฅ์ ์„ ๋ชจ๋‘ ์ง€๋‹Œ ๋ฐฉ์‹์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทผ๋ฐ ๋งŒ์•ฝ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ •๊ณผ ๊ฐ™์€ ์–ด๋–ค ํŠน์ •ํ•œ ํ–‰๋™ ์ดํ›„์— ์ฆ‰์‹œ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋˜์–ด์•ผ ํ•  ๋•Œ๋Š” ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ?

์ด๋Š” On-Demand ISR๋กœ Next.js ์„œ๋ฒ„์— ์ง์ ‘ revalidate ์š”์ฒญ ๋‚ ๋ ค์ฃผ๋ฉด ๋œ๋‹ค.

import { NextApiRequest, NextApiResponse } from "next";

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  try {
    await res.revalidate("/");
    return res.json({ revalidate: true });
  } catch (err) {
    console.log(err);
    res.status(500).send("Revalidation Failed");
  }
}

Page Router์˜ ์žฅ๋‹จ์ 

ํŽ˜์ด์ง€ ๋ผ์šฐํŒ…์˜ ์žฅ์ ์„ ๋จผ์ € ์ •๋ฆฌํ•ด๋ณด์ž.

์žฅ์ ๋‹จ์ 
ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ธฐ๋ฐ˜ ๊ฐ„ํŽธํ•œ ํŽ˜์ด์ง€ ๋ผ์šฐํŒ… ์ œ๊ณต๋ฒˆ๊ฑฐ๋กœ์šด ํŽ˜์ด์ง€๋ณ„ ๋ ˆ์ด์•„์›ƒ ์„ค์ •
๋‹ค์–‘ํ•œ ๋ฐฉ์‹์˜ ์‚ฌ์ „ ๋ Œ๋”๋ง ์ œ๊ณตํŒจ์ด์ง€ ์ปดํฌ๋„ŒํŠธ์— ์ง‘์ค‘๋˜๋Š” ๋ฐ์ดํ„ฐ ํŒจ์นญ
-๋ถˆํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ๋„ JS ๋ฒˆ๋“ค์— ํฌํ•จ

์—ฌ๊ธฐ์„œ ํŽ˜์ด์ง€ ๋ผ์šฐํ„ฐ์˜ ๋‹จ์ ์„ ๋ณด์™„ํ•œ App Router๊ฐ€ ๋“ฑ์žฅํ•˜๊ฒŒ ๋œ๋‹ค.

๋‹ค์Œ์—” App Router์— ๋Œ€ํ•ด ์ •๋ฆฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹น๐Ÿ‘‹๐Ÿป