Framework/Next.js

[Next.js & React] ํŽ˜์ด์ง€ ์‚ฌ์ „ ๋ Œ๋”๋ง & ๋ฐ์ดํ„ฐ ํŽ˜์นญ

yuri lee 2022. 11. 21. 22:07
๋ฐ˜์‘ํ˜•
์ด ๊ธ€์€ udemy์˜ Next.js & React - ์™„๋ฒฝ ์ •๋ณต ๊ฐ€์ด๋“œ (incl. Two Paths) ๊ฐ•์ขŒ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ •๋ฆฌํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

86. ๋ชจ๋“ˆ ๊ฐœ์š”

Next.js๋ฅผ ์ด์šฉํ•˜๋ฉด ํ’€์Šคํƒ React ์•ฑ์„ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Next.js๋Š” ์„œ๋ฒ„ ์‚ฌ์ด๋“œ์—์„œ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ๋ Œ๋”๋ง ํ•ด์ค๋‹ˆ๋‹ค. Next.js๋Š” ์ฝ”๋“œ ์‹คํ–‰์— ์žˆ์–ด์„œ ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ React ์•ฑ์ด ์‹คํ–‰๋˜๋Š” ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ € ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ์—์„œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ๋„ ๋„์›€์„ ์ค๋‹ˆ๋‹ค. ํŽ˜์ด์ง€์— ํ‘œ์‹œ๋˜์–ด์•ผ ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•˜๊ฑฐ๋‚˜ ๋กœ๋”ฉํ•˜๋Š” ์ž‘์—…์„ ๋•๋Š”๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค. 

 

  1. ๋ฐ์ดํ„ฐ fetching์ด ๋ฌด์—‡์ธ๊ฐ€
  2. Static VS Server-side Page
  3. ์–ด๋–ป๊ฒŒ ๋ฐ์ดํ„ฐ fetch ํ•˜๋Š”๊ฐ€

์ด ์˜๋ฏธ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์‚ดํŽด๋ณด๋„๋ก ํ•ฉ์‹œ๋‹ค.  

 

87. ๊ธฐ์กด React App (๊ทธ๋ฆฌ๊ณ  ๋ฐ์ดํ„ฐ fetching)์˜ ๋ฌธ์ œ์ 

 

์‚ฌ์šฉ์ž๋“ค์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์‹ค์งˆ์ ์œผ๋กœ ํŽ˜์ด์ง€์— ๋กœ๋”ฉ๋˜๊ธฐ๊นŒ์ง€๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฐฑ์—”๋“œ API๋ฅผ ์ด์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ํŽ˜์นญํ•˜๋Š” ์‹ค์ œ ํŽ˜์ด์ง€์—์„œ๋Š” ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ์— ๋ช‡ ์ดˆ๊ฐ€ ์†Œ์š”๋  ์ˆ˜ ์žˆ์–ด ์ง€์—ฐ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์˜ ์ตœ์ ํ™”๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ๋” ํฐ ๋ฌธ์ œ๋Š” ๊ฒ€์ƒ‰ ์—”์ง„ ์ตœ์ ํ™”์— ์žˆ์Šต๋‹ˆ๋‹ค. HTML ์ฝ”๋“œ๋Š” ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‹ค์‹œ ์ „์†ก๋˜๋ฉด์„œ ๊ฒ€์ƒ‰ ์—”์ง„์€ ์ด์™€ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ด…๋‹ˆ๋‹ค. ์ฝ˜์ฒธ์ธ ๊ฐ€ ์ „ํ˜€ ์—†๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ง์ž…๋‹ˆ๋‹ค. 

 

๋”ฐ๋ผ์„œ ์ฝ˜ํ…์ธ ๊ฐ€ ์ค‘์š”ํ•˜๋ฉฐ ๊ฒ€์ƒ‰ ์—”์ง„์ด ํ•ด๋‹น ์ฝ˜ํ…์ธ ๋ฅผ ์—ด๋žŒํ•˜๊ณ  ๋˜ ์ธ๋ฑ์‹ฑ ํ•˜๊ฒŒ ํ•˜๋ ค๋ฉด ์žฌ์ „์†ก ๋ฐฉ์‹์€ ์ ํ•ฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.  ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ์„ ํ•ด์•ผ ํ•˜๋Š” ์›น์•ฑ์ด๊ฑฐ๋‚˜, React๋กœ ๊ตฌ์ถ•๋œ ๊ด€๋ฆฌ์ž ๋Œ€์‹œ๋ณด๋“œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” ๊ฒ€์ƒ‰ ์—”์ง„์ด ์ƒ๊ด€์—†์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ธ”๋กœ๊ทธ์™€ ์‡ผํ•‘๋ชฐ์ฒ˜๋Ÿผ ๋งŽ์€ ์ฝ˜ํ…์ธ ๊ฐ€ ์žˆ๋Š” ์•ฑ์˜ ๊ฒฝ์šฐ ๊ฒ€์ƒ‰ ์—”์ง„์— ๋…ธ์ถœ๋˜๊ธธ ๋ฐ”๋ž„ ํ…๋ฐ ์ด๋Ÿฐ ๊ฒฝ์šฐ, ๋ฐ์ดํ„ฐ๋ฅผ ์žฌ์ „์†ก ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ๋ฐ”๋žŒ์งํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 

ํ‘œ์ค€ React๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์˜ค๋ฅ˜๋กœ, ๋ฐ์ดํ„ฐ๋ฅผ fetching ํ•˜๋Š” ์ผ์ด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋กœ๋”ฉ๋œ ํ›„์—ฌ์•ผ ํ•œ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค. ์ฆ‰ ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ fetching ํ•˜๊ณ  ํ™”๋ฉด์— ๋ Œ๋”๋ง๋œ ํ›„์— ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ ์„ Next.js์˜ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๊ธฐ๋Šฅ๊ณผ ๋‚ด์žฅ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

 

88. NextJS๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ์ค€๋น„ํ•˜๊ณ , ์‚ฌ์ „ ๋ Œ๋”๋ง์„ ํ•˜๋Š” ๋ฐฉ์‹

์–ด๋–ค ํŽ˜์ด์ง€๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•ด๋ด…์‹œ๋‹ค. pages ํด๋”์—์„œ ํŽ˜์ด์ง€ ํŒŒ์ผ์„ ๋กœ๋”ฉํ•˜๋Š” some-route ํŽ˜์ด์ง€๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํ•„์š”๋กœ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ผ์šฐํŠธ์— ์š”์ฒญ์ด ์ „์†ก๋œ ๊ฒฝ์šฐ ์ฆ‰ ์‚ฌ์šฉ์ž๊ฐ€ ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ ๋ฐฉ๋ฌธํ•˜๋ฉด Next.js๊ฐ€ ์‚ฌ์ „ ๋ Œ๋”๋ง๋œ ํŽ˜์ด์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ํ‘œ์ค€ React์™€์˜ ์ฐจ์ด์ ์ž…๋‹ˆ๋‹ค. ํ‘œ์ค€ React๋ผ๋ฉด ๋นˆ HTML ํŒŒ์ผ๊ณผ ๋ชจ๋“  JS ์ฝ”๋“œ๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  JS ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋ฉด ์Šคํฌ๋ฆฐ์— ๋‚ด์šฉ์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๊ทธ ์†๋„๊ฐ€ ๋นจ๋ผ์„œ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฌธ์ œ๋กœ ๋ณด์ด์ง€ ์•Š์„ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ผ๋ฐ˜ DOM ๊ตฌ์กฐ ์™ธ์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋กœ๋”ฉ๋  ๋•Œ์—๋Š” ์‹œ๊ฐ„์ด ์†Œ์š”๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.  ์‚ฌ์ „ ๋ Œ๋”๋ง ๋˜์ง€ ์•Š์•˜์„ ๋•Œ ๋ง์ž…๋‹ˆ๋‹ค.

 

์ด ์ž‘์—…์„ Nextj๊ฐ€ ํ•˜๋Š”๋ฐ, ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†ก๋œ ๋’ค์—๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋”ฉํ•˜๋Š” ๋Œ€์‹  ํŽ˜์ด์ง€์™€ ํ•„์š”ํ•  ๋ฒ•ํ•œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” HTML ์ฝ˜ํ…์ธ ๋ฅผ ์‚ฌ์ „์— ๋ Œ๋”๋ง ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์ „์— HTML ํŒŒ์ผ์„ ์™„์„ฑํ•ด๋†“๊ณ , ์™„์ „ํžˆ ์ฑ„์›Œ์ง„ HTML ํŒŒ์ผ์„ ํด๋ผ์ด์–ธํŠธ, ์ฆ‰ ํŽ˜์ด์ง€์˜ ๋ฐฉ๋ฌธ์ž์—๊ฒŒ ์ „์†กํ•ฉ๋‹ˆ๋‹ค. SEO ๊ด€์ ์—์„œ ๋งค์šฐ ํ›Œ๋ฅญํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ Interactive React ์•ฑ์€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. interactive ์•ฑ์„ ๋งŒ๋“ค๋ ค๊ณ  React๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์•„๋‹ˆ๋ผ๋ฉด HTML์ด๋‚˜ Css ์•ฑ์„ ๊ตฌ์ถ•ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. React๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” ํฌ๋Ÿผ ์ ‘์†์ด๋‚˜ ์—๋Ÿฌ ๊ฒ€์ฆ ๋“ฑ์˜ ๋ฒ„ํŠผ ํด๋ฆญ์— ๋ฐ˜์‘ํ•ด์„œ ์‚ฌ์šฉ์ž ์ƒํ˜ธ์ž‘์šฉ์„ ํ•˜๊ธฐ ์œ„ํ•จ์ž…๋‹ˆ๋‹ค. 

 

Next.js๋Š” ๋‹จ์ˆœํžˆ ์‚ฌ์ „ ๋ Œ๋”๋ง๋œ ํŽ˜์ด์ง€๋ฅผ ์žฌ์ „์†กํ•˜๋Š” ๋ฐ ๊ทธ์น˜์ง€ ์•Š๊ณ , ํฌํ•จ๋œ JS ์ฝ”๋“œ๋ฅผ ๋ชจ๋‘ ์žฌ์ „์†กํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์žฌ์ „์†ก์„ ํ•ด๋‹น ํŽ˜์ด์ง€์— ๋Œ€ํ•ด Hydrate ํ•œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.  ์žฌ์ „์†ก๋œ JS ์ฝ”๋“œ๋Š” ๋‚˜์ค‘์— ์‚ฌ์ „ ๋ Œ๋”๋ง ๋œ ํŽ˜์ด์ง€๋ฅผ ๋Œ€์ฒดํ•˜๊ณ  ์ด์— React๊ฐ€ ์•Œ๋งž๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.  ์ฒ˜์Œ ์žฌ์ „์†กํ•œ ์‚ฌ์ „ ๋ Œ๋”๋ง๋œ ํŽ˜์ด์ง€์—๋Š” ์ฃผ์š” ์ฝ˜ํ…์ธ ๊ฐ€ ๋ชจ๋‘ ํฌํ•จ๋˜์–ด ์žˆ๋Š” ์ƒํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด์— ๊ฒ€์ƒ‰ ์—”์ง„ ํฌ๋กค๋Ÿฌ๋„ ์ „์ฒด ํŽ˜์ด์ง€์— ์ด๋ฏธ ํฌํ•จ๋œ ๋ชจ๋“  ์ฝ˜ํ…์ธ ๋ฅผ ์‚ดํŽด๋ณด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋•Œ ์ƒํ˜ธ์ž‘์šฉ ํŽ˜์ด์ง€๊ฐ€ ์•„๋‹ˆ์–ด๋„ ํฌ๋กค๋Ÿฌ๋Š” ์ฝ˜ํ…์ธ ๋งŒ ํ™•์ธํ•˜๋‹ˆ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๊ฒŒ ์‚ฌ์ „ ๋ Œ๋”๋ง์˜ ๊ฐœ๋…์ž…๋‹ˆ๋‹ค. ๋” ์ •ํ™•ํžˆ ๋งํ•˜๋ฉด Next.js๋Š” ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „์— ์ค€๋น„ํ•˜๋Š”๋ฐ, ์ด๋•Œ ๋ชจ๋“  Html ์ฝ˜ํ…์ธ ๋ฅผ ์‚ฌ์ „์— ๊ตฌ์ถ•ํ•˜๊ณ  ํ•„์š”ํ•  ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์ „์— ๋กœ๋”ฉํ•˜๋Š” ๋ฐฉ์‹์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. ์‚ฌ์ „ ๋ Œ๋”๋ง์€ ์˜ค์ง ์ตœ์ดˆ ๋กœ๋”ฉํ•  ๋•Œ๋งŒ ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค. 

 

Next.js์™€ React๋กœ ๊ตฌ์ถ•๋œ ํŽ˜์ด์ง€์—์„œ๋Š” ํŽ˜์ด์ง€์˜ Hydrate, ์ฆ‰ ์ฒซ ๋ฒˆ์งธ ๋ Œ๋”๋ง์ด ๋๋‚˜๊ณ  ๋‚˜๋ฉด ๋‹ค์‹œ ํ‘œ์ค€ ์‹ฑ๊ธ€ ํŽ˜์ด์ง€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์œผ๋กœ ๋Œ์•„๊ฐ‘๋‹ˆ๋‹ค. ์ด๋•Œ๋ถ€ํ„ฐ React๊ฐ€ ํ”„๋ก ํŠธ์—”๋“œ์—์„œ ๋ชจ๋“  ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.  Next.js์—๋Š” ๋‘ ๊ฐ€์ง€ pre-Rendering ์–‘์‹์ด ์žˆ์Šต๋‹ˆ๋‹ค. Static Generation, Server-side Rendering ์ž…๋‹ˆ๋‹ค. SSR๊ณผ ์ •์  ์ƒ์„ฑ์˜ ๊ฐ€์žฅ ํฐ ์ฐจ์ด๋Š” Static Generation์€ ๋นŒ๋“œ๋˜๋Š” ๋™์•ˆ ๋ชจ๋“  ํŽ˜์ด์ง€๊ฐ€ ์‚ฌ์ „ ์ƒ์„ฑ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ prod์šฉ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ์ถ•ํ•œ๋‹ค๋ฉด ๋ฐฐํฌ ์ „์— ๋ชจ๋“  ํŽ˜์ด์ง€๊ฐ€ ์ค€๋น„๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. Server-side Rendering(SSR)์˜ ๊ฒฝ์šฐ์—๋Š” ๋ฐฐํฌ ํ›„ ์š”์ฒญ์ด ์„œ๋ฒ„๊นŒ์ง€ ์˜ค๋Š” ๋ฐ”๋กœ ๊ทธ๋•Œ ๋ชจ๋“  ํŽ˜์ด์ง€๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. 

 

89. "getStaticProps"๋ฅผ ํ†ตํ•œ static generation

์ผ๋ฐ˜์ ์œผ๋กœ ๊ถŒ์žฅ๋˜๋Š” ๊ฐœ๋…์ž…๋‹ˆ๋‹ค. ๋นŒ๋“œํ•˜๋Š” ๋™์•ˆ ํŽ˜์ด์ง€๋ฅผ pre-Rendering ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. pre-Rendering ์ด๋ผ๋Š” ๊ฒƒ์€ ์ฝ˜ํ…์ธ ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋ชจ๋“  HTML ์ฝ”๋“œ์™€ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์ „์— ์ค€๋น„์‹œ์ผœ ๋†“๋Š”๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค. ๋ณดํ†ต ์„œ๋ฒ„ ์‚ฌ์ด๋“œ์—์„œ๋งŒ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ๋ฅผ ๋นŒ๋“œ ํ”„๋กœ์„ธ์Šค ๋™์•ˆ ์‹คํ–‰๋˜๋„๋ก ํ—ˆ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋นŒ๋“œ ์‹œ๊ฐ„์€ ๋ฐฐํฌ ์ „ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ์ถ•ํ•  ๋•Œ๋ฅผ ๋งํ•ฉ๋‹ˆ๋‹ค. ๋นŒ๋“œ ์‹œ๊ฐ„ ์ค‘ ํŽ˜์ด์ง€๊ฐ€ ์‚ฌ์ „์— ๊ตฌ์ถ•๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐฐํฌ๋˜๊ณ  ๋‚˜๋ฉด ๊ตฌ์ถ•๋œ ํŽ˜์ด์ง€๋Š” ์„œ๋ฒ„๋‚˜ ์•ฑ์„ ์‹คํ–‰์‹œํ‚ค๋Š” CDN์„ ํ†ตํ•ด์„œ ์บ์‹œ๋กœ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ์ด์— ์‚ฌ์ „ ๊ตฌ์ถ•๋œ ํŽ˜์ด์ง€๋ฅผ ํ†ตํ•ด์„œ ์ฆ‰์‹œ ์ž…๋ ฅ ์š”์ฒญ์ด ์‹คํ–‰๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

 

ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋Š” ํŠน์ˆ˜ํ•œ ๋น„๋™๊ธฐ ํ•จ์ˆ˜์ธ getStaticProps()๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.  ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ์˜ ๋‚ด๋ถ€์— ์žˆ์–ด์•ผ ํ•˜๋ฉฐ, ๋‹ค๋ฅธ React ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์•„๋‹Œ pages ํด๋”์˜ component ํŒŒ์ผ ๋‚ด๋ถ€๊ฐ€ ๊ทธ ์œ„์น˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

export async function getStaticProps(context) {...}

์ด๋Š” ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋กœ ๊ทธ ์•ˆ์— await ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. getStaticProps ๋‚ด์— ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋Š” ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์žฌ์ „์†ก๋˜๋Š” ์ฝ”๋“œ๋กœ ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฆ‰ ํ•ด๋‹น ํ•จ์ˆ˜ ๋‚ด์— ํฌํ•จํ•˜๋Š” ์ฝ”๋“œ๋Š” ํด๋ผ์ด์–ธํŠธ๋Š” ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. (ex. db credential์„ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ) 

 

90. NextJS๋Š” ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์ „ ๋ Œ๋”๋ง

์†Œ์Šค๋ฅผ ๋ณด๋ฉด Next.js๊ฐ€ ์ƒ์„ฑํ•œ ์ด ํŽ˜์ด์ง€์˜ ์†Œ์Šค๋Š” ์ด์ „ ํ‘œ์ค€ React ์•ฑ์—์„œ ๋ดค๋˜ ๊ฒƒ๊ณผ๋Š” ๋‹ค์†Œ ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. Product 1,2,3 ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํŽ˜์ด์ง€ ์†Œ์Šค๊ฐ€ ๋ฐ”๋กœ ์„œ๋ฒ„์—์„œ๋ถ€ํ„ฐ ๋ฐ›๋Š” ์‹ค์ œ ์‘๋‹ต์ด๋ผ๋Š” ์ ์„ ๊ธฐ์–ตํ•˜์‹œ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—๋Š” ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋”ฉ๋  ๋•Œ์˜ ๊ฐœ๋ฐœ ์„œ๋ฒ„์—์„œ ๋ฐ›๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ์š”์ฒญ์ด ์ฒ˜์Œ ์ „์†ก๋œ ์„œ๋ฒ„์ž…๋‹ˆ๋‹ค. ๋ฐ”๋กœ ์ด ์ฝ˜ํ…์ธ ๋ฅผ ๊ฒ€์ƒ‰ ์—”์ง„์ด ๋ณด๊ฒŒ ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฝ˜ํ…์ธ ๊ฐ€ ์ด๋ฏธ ํฌํ•จ๋˜์–ด ์žˆ์–ด SEO ๊ด€์ ์—์„œ๋Š” ํ›Œ๋ฅญํ•ฉ๋‹ˆ๋‹ค. 

import Head from "next/head";
import Image from "next/image";
import styles from "../styles/Home.module.css";

function HomePage(props) {
  return (
    <ul>
      <li>Product 1</li>
      <li>Product 2</li>
      <li>Product 3</li>
    </ul>
  );
}

export default HomePage;
<!DOCTYPE html><html><head><style data-next-hide-fouc="true">body{display:none}</style><noscript data-next-hide-fouc="true"><style>body{display:block}</style></noscript><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills.js?ts=1668347788930"></script><script src="/_next/static/chunks/webpack.js?ts=1668347788930" defer=""></script><script src="/_next/static/chunks/main.js?ts=1668347788930" defer=""></script><script src="/_next/static/chunks/pages/_app.js?ts=1668347788930" defer=""></script><script src="/_next/static/chunks/pages/index.js?ts=1668347788930" defer=""></script><script src="/_next/static/development/_buildManifest.js?ts=1668347788930" defer=""></script><script src="/_next/static/development/_ssgManifest.js?ts=1668347788930" defer=""></script><noscript id="__next_css__DO_NOT_USE__"></noscript></head><body><div id="__next"><ul><li>Product 1</li><li>Product 2</li><li>Product 3</li></ul></div><script src="/_next/static/chunks/react-refresh.js?ts=1668347788930"></script><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/","query":{},"buildId":"development","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>

Next.js๋Š” ๋™์  ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. 

 

91. getStaticProps ์ถ”๊ฐ€ํ•˜๊ธฐ

getStaticProps ํ•จ์ˆ˜๋Š” ๋ชจ๋“  ํŽ˜์ด์ง€ ํŒŒ์ผ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๊ณ  ํŽ˜์ด์ง€์—๋งŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‚ด๋ณด๋‚ด์•ผ(export) ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด Next.js๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ์ƒ์„ฑํ•  ๋•Œ ์‚ฌ์šฉ์ž๋ฅผ ๋Œ€์‹ ํ•˜์—ฌ ์ด getStaticProps ํ•จ์ˆ˜๋„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ์ด ํŽ˜์ด์ง€๊ฐ€ ์‚ฌ์ „ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•˜๋Š” ํŽ˜์ด์ง€์ž„์„ Next.js์— ์•Œ๋ ค์ค๋‹ˆ๋‹ค. Next.js๋Š” ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ๋ Œ๋”๋งํ•˜์ง€๋งŒ ์ดํ›„์— Next.js๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „์— ๋ Œ๋”๋งํ•˜์ง€ ์•Š๊ฒŒ ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์›๋‹ˆ๋‹ค. Next.js๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  JSX ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ ์™ธ์—๋„ ์ปดํฌ๋„ŒํŠธ ํŒŒ์ผ์—์„œ getStaticProps ํ•จ์ˆ˜๋ฅผ ์ฐพ์œผ๋ฉด ๊ทธ ํ•จ์ˆ˜๋„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ํ‘œ์ค€ React ์•ฑ์—์„œ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ์‹ useEffect๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๋กœ๋“œํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์ „์— ๊ทธ๋ฆฌ๊ณ  Next.js๊ฐ€ ์ด ์ปดํฌ๋„ŒํŠธ ํŽ˜์ด์ง€๋ฅผ pre-Rendering ํ•˜๊ธฐ ์ „ ๋ฐ์ดํ„ฐ๋ฅผ ํ”„๋ฆฌํŽ˜์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ export async function getStaticProps()์œผ๋กœ getStaticProps๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒ๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ์ด๋ฆ„์ด getStaticProps๋ผ์„œ props ํ‚ค๊ฐ€ ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๊ณ  ์ด ํ•จ์ˆ˜๊ฐ€ ํ•˜๋Š” ์ผ์€ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ค€๋น„ํ•˜๋Š” ๊ฒ๋‹ˆ๋‹ค.

export async function getStaticProps() {
  return {
    props: {
      products: [{ id: "p1", title: "Product 1" }],
    },
  };

์ฆ‰ ์ด props ๊ฐ์ฒด๋ฅผ ์ค€๋น„ํ•˜๋Š” ๊ฑฐ์ฃ . ํŒŒ์ผ์— getStaticProps ํ•จ์ˆ˜๊ฐ€ ์žˆ์œผ๋ฉด Next.js์—์„œ ๋จผ์ € ์ด ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๋‘ ๋ฒˆ์งธ๋กœ ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„์—์„  ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜์— ๋Œ€ํ•œ props๋ฅผ ์ค€๋น„ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด์ฃ . ๋”ฐ๋ผ์„œ getStaticProps ํ•จ์ˆ˜์—์„œ๋Š” ์›ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ œํ•œ ์—†์ด ์‹คํ–‰ ๊ฐ€๋Šฅํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ์—์„œ๋Š” ์ ˆ๋Œ€ ๋ณผ ์ˆ˜ ์—†๋Š” ์ฝ”๋“œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ fetchingํ•˜๊ณ  ์ด HomePage ์ปดํฌ๋„ŒํŠธ์— props๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๊ทธ๋ž˜์„œ ์—ฌ๊ธฐ์„œ props๋ฅผ ๊ฐ์ฒด์™€ ๋™์ผํ•˜๊ฒŒ ์„ค์ •ํ•ด์„œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฐ›๋Š” props๊ฐ€ product ๋ถ€๋ถ„์—์„œ๋„ ๊ฐ์ฒด๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ ๊ฐ์ฒด๋Š” ๊ฐ€๋ น id: 'p1'์ด๊ณ  title: 'Product 1'์ธ ์ด๋Ÿฐ ์‹์˜ ๋ฐฐ์—ด์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. getStaticProps๋Š” props ํ‚ค๋ฅผ ํฌํ•จํ•œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๊ณ , ์ด๋Š” ํ•„์ˆ˜ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค. ์ด ๊ฐ์ฒด๋Š” ๋ฐฐ์—ด์„ ๋ณด์œ ํ•˜๋Š” products ํ‚ค๊ฐ€ ์žˆ๋Š” ๊ฐ์ฒด์ด๊ณ  ๋ฐฐ์—ด์€ Product ๊ฐ์ฒด์˜ ๋ฐฐ์—ด์ด์ฃ . ๊ทธ๋ฆฌ๊ณ  Next.js๊ฐ€ ๋จผ์ € ์ด getStaticProps ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ด ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด HomePage์˜ props์—์„œ ์ด๋ฅผ ์ˆ˜์‹ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์‚ฌ์ „์— ๋‘ ๊ฐ€์ง€ ์ž‘์—…์„ ๋ชจ๋‘ ์ˆ˜ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ์—์„œ๋Š” ์ด ์ฝ”๋“œ ๋ชจ๋‘ ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ๋ชจ๋“  ๊ฒƒ์€ ๋นŒ๋“œ๋˜๋Š” ์‹œ๊ฐ„ ๋™์•ˆ ํ˜น์€ ์‚ฌ์šฉ ์ค‘์ธ ์ด ๊ฐœ๋ฐœ ์„œ๋ฒ„์˜ ์ผ๋ถ€๋กœ ๊ฐœ๋ฐœ ์ค‘์— ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

Next.js ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๊ฐ€๋ณด๋ฉด Product 1์ด ๋ณด์ž…๋‹ˆ๋‹ค. ํ•˜๋“œ ์ฝ”๋”ฉํ•˜๊ธด ํ–ˆ์ง€๋งŒ ์ด๋ฏธ getStaticProps๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฑฐ์ฃ . ์ด ํŽ˜์ด์ง€์˜ ํŽ˜์ด์ง€ ์†Œ์Šค๋ฅผ ๋ณด๋ฉด ์ด ๋ฐ์ดํ„ฐ ์ด Product 1์˜ ๋ฐ์ดํ„ฐ๋Š” ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ณด๋‚ด์ง„ ํŽ˜์ด์ง€์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค. ์ฆ‰ Product ๋ฐ์ดํ„ฐ ํŽ˜์นญ์€ ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„์—์„œ ๋ฐœ์ƒํ•œ ๊ฑฐ์ฃ .

๊ฐœ๋ฐœ์ž ๋„๊ตฌ์˜ Sources ํƒญ์œผ๋กœ ๊ฐ€์„œ JavaScript ์ฝ”๋“œ ํŒŒ์ผ์„ ๋ณด๋ฉด ์ด ์ฝ”๋“œ๋Š” ์•„๋ฌด ๊ณณ์—์„œ๋„ ๋ณด์ด์ง€ ์•Š์„ ๊ฒ๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ์— ์ œ๊ณต๋˜๋Š” ์ฝ”๋“œ๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด๋Š” getStaticProps์˜ ์ฝ”๋“œ๊ฐ€ ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ์—์„œ ์‹คํ–‰๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ฒ„ ์ธก ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณผ ์ˆ˜ ์—†๋Š” ํฌ๋ฆฌ๋ด์…œ(credential)์„ ์“ธ ์ˆ˜ ์žˆ๊ณ  ์˜ˆ๋ฅผ ๋“ค์–ด ํŒŒ์ผ ์‹œ์Šคํ…œ์— ์ ‘๊ทผํ•˜๋Š” ์ฝ”๋“œ์™€ ๊ฐ™์ด ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

 

92. ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ์ฝ”๋“œ ์‹คํ–‰ํ•˜๊ธฐ & FileSystem ์‚ฌ์šฉํ•˜๊ธฐ

getStaticProps ๋‚ด๋ถ€์˜ ๋ชจ๋“  ์ฝ”๋“œ๊ฐ€ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ์—์„œ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๊ธฐ๋Šฅ๊ณผ ํ•จ๊ป˜ ์‹คํ–‰๋œ๋‹ค๋Š” ์ ์„ ํ™œ์šฉํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. 

import path from "path";
import fs from "fs/promises";

export default function HomePage(props) {
  const { products } = props;

  return (
    <ul>
      {products.map((product) => (
        <li key={product.id}>{product.title}</li>
      ))}
    </ul>
  );
}

export async function getStaticProps() {
  const filePath = path.join(process.cwd(), "data", "dummy-backend.json");
  const jsonData = await fs.readFile(filePath);
  const data = JSON.parse(jsonData);

  return {
    props: {
      products: data.products,
    },
  };
}

์ด ํŒจํ‚ค์ง€๋Š” Node.js์˜ ํ•ต์‹ฌ ๋ชจ๋“ˆ์ž…๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ € ์ธก JavaScript๊ฐ€ ํŒŒ์ผ ์‹œ์Šคํ…œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ์—์„œ๋Š” fs ๋ชจ๋“ˆ ์ž‘์—…์ด ์•ˆ๋ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ์ด ํ”„๋กœ์ ํŠธ ํŒŒ์ผ ์‹œ์Šคํ…œ์€ ๋ฐฉ๋ฌธ์ž์—๊ฒŒ ์ œ๊ณต๋˜์ง€ ์•Š์•„์„œ ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

 Next.js๋Š” ๋งค์šฐ ๋˜‘๋˜‘ํ•ด์„œ getStaticProps๋‚˜ ๋‚˜์ค‘์— ๋ฐฐ์šฐ๋Š” ํ•จ์ˆ˜์—์„œ๋งŒ ์“ฐ์ด๋Š” ์ž„ํฌํŠธ๋ฅผ ํ™•์ธํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์ฝ”๋“œ ๋ฒˆ๋“ค์—์„œ๋Š” ์ด ์ž„ํฌํŠธ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์ฝ”๋“œ ๋ธŒ๋ผ์šฐ์ € ์ธก React ์•ฑ ์ฝ”๋“œ๊ฐ€ ์ค€๋น„๋  ๋•Œ ๊ทธ ์ž„ํฌํŠธ๋Š” ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค Next.js๊ฐ€ ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ์—์„œ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ์„ ์•Œ๊ณ  ์ฝ”๋“œ๋ฅผ ๋‚˜๋ˆ„๋Š” ๊ฑฐ์ฃ . 

๋”ฐ๋ผ์„œ ์ผ๋ฐ˜์ ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ ์ฝ”๋“œ๋Š” ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์ฝ”๋“œ์— ํฌํ•จ๋˜๊ณ  ์ด ์ž„ํฌํŠธ์™€ ์ด ์ฝ”๋“œ๋Š” ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด์ œ fs๋กœ ์ด dummy-backend.json ํŒŒ์ผ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. fs.readFile์ด๋‚˜ readFileSync ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. readFileSync๋Š” ํŒŒ์ผ์„ ๋™๊ธฐ์ ์œผ๋กœ ์ฝ๊ณ  ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์‹คํ–‰์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด์— readFile์€ ๊ณ„์†ํ•˜๋ ค๋ฉด ์ฝœ๋ฐฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Node.js ๋ชจ๋“ˆ์˜ ํŠน์ˆ˜ ๋ฒ„์ „์ธ fs/promises์—์„œ ํŒŒ์ผ ์‹œ์Šคํ…œ์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด readFile์€ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ํ•จ์ˆ˜๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์— await์„ ์•ž์— ๋ถ™์—ฌ์ค๋‹ˆ๋‹ค. ์ด์ œ readFile์€ ์ฝ์–ด ์˜ค๋ ค๊ณ  ํ•˜๋Š” ํŒŒ์ผ์˜ ๊ฒฝ๋กœ๋งŒ ์žˆ์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ path๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ์ด๋ฆ„์„ filePath๋กœ ์ง€์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ๋กœ๋Š” dummy-backend.json ํŒŒ์ผ๋กœ ์—ฐ๊ฒฐ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

path ๋ชจ๋“ˆ์€ ๊ฒฝ๋กœ๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐ ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์ด ์žˆ๋Š” ๋ชจ๋“ˆ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ path๋ฅผ ์“ฐ๊ณ  join ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•ด์„œ readFile์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ๋กœ๋ฅผ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.  Node.js์—์„œ ์ „์—ญ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” process ๊ฐ์ฒด๋ฅผ ํ™œ์šฉํ•˜์—ฌ  process์— cwd ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (cwd๋Š” ํ˜„์žฌ ์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ๋ผ๋Š” ๋œป) ์ด ํŒŒ์ผ์ด ์‹คํ–‰๋  ๋•Œ Next.js๊ฐ€ ์ด๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๋ชจ๋“  ํŒŒ์ผ์ด ๋ฃจํŠธ ํ”„๋กœ์ ํŠธ ํด๋”์— ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ทจ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ํ˜„์žฌ ์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ๋Š” pages ํด๋”๊ฐ€ ์•„๋‹Œ ์ „์ฒด ํ”„๋กœ์ ํŠธ ํด๋”๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ cwd๋กœ Node.js path.join ๋ฉ”์„œ๋“œ์— ์ด ์ „์ฒด ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์‹œ์ž‘ํ•œ๋‹ค๊ณ  ์•Œ๋ ค์ฃผ๊ณ  ์‰ผํ‘œ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ์ธ์ˆ˜๋Š” data ํด๋”๋กœ ๊ฐ€์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— 'data'์ž…๋‹ˆ๋‹ค. 

JSON ํŒŒ์ผ์—์„œ jsonData๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์‹ค์ œ ๋ฐ์ดํ„ฐ(data)๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด JSON.parse(jsonD)๋ฅผ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค. JSON์€ ์ „์—ญ์ ์œผ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด๊ณ  ๋ธŒ๋ผ์šฐ์ € ์ธก์—์„œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Node.js์—์„œ๋„ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ์ด๊ฒƒ์€ jsonData๋ฅผ ํŒŒ์‹ฑํ•˜๊ณ  ์ผ๋ฐ˜ JavaScript ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ data๋Š” ๋ฐฐ์—ด์„ ํฌํ•จํ•˜๋Š” products ํ‚ค๊ฐ€ ์žˆ๋Š” ๊ฐ์ฒด๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ์ด์ œ ์ด data๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” props๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ. props์— ํฌํ•จ๋œ products๋Š” data.products๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ํŒŒ์ผ์—์„œ ํŽ˜์น˜ํ•œ products๋Š” ์ด์ œ ์ด ๊ฐ์ฒด์˜ products์— ๊ฐ’์œผ๋กœ ์ „๋‹ฌ๋˜๋ฏ€๋กœ ๊ถ๊ทน์ ์œผ๋กœ Next.js๊ฐ€ ์ด ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ์ด ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜์— props๋ฅผ ํ†ตํ•ด ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋จผ์ € ์ด ํ•จ์ˆ˜๋ฅผ ๊ฑฐ์น˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด์ œ ๋ชจ๋“  ๊ฒƒ์„ ์ €์žฅํ•˜๊ณ  localhost:3000์„ ์ƒˆ๋กœ ๊ณ ์นจํ•˜๋ฉด ์—ฌ๊ธฐ์— ์„ธ ๊ฐœ์˜ Product๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค ํŽ˜์ด์ง€ ์†Œ์Šค๋กœ ๋Œ์•„๊ฐ€ ๋ณด๋ฉด ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์ „ ๋ Œ๋”๋ง ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. 

ํด๋ผ์ด์–ธํŠธ์— ๋„๋‹ฌํ•˜์ง€ ์•Š๋Š” ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” getStaticProps์˜ ๋„์›€์œผ๋กœ ์‚ฌ์ „ ๋ Œ๋”๋ง ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” Next.js๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ๋ Œ๋”๋งํ•  ๋•Œ๋งŒ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

 

93. ๋‚ด๋ถ€์—์„œ ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š” ์ผ

build ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. 

npm run build
Route (pages)                              Size     First Load JS
โ”Œ โ— /                                      404 B          79.3 kB
โ”œ   /_app                                  0 B            78.9 kB
โ”œ โ—‹ /404                                   212 B          79.1 kB
โ”” λ /api/hello                             0 B            78.9 kB
+ First Load JS shared by all              79.1 kB
  โ”œ chunks/framework-aefaf282dc32bbc7.js   45.7 kB
  โ”œ chunks/main-5cebf592faf0463a.js        31.8 kB
  โ”œ chunks/pages/_app-aba2de2b7ae6fcb3.js  390 B
  โ”œ chunks/webpack-2369ea09e775031e.js     1.02 kB
  โ”” css/49861c0d8668ac82.css               185 B

λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)
โ—‹  (Static)  automatically rendered as static HTML (uses no initial props)
โ—  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)

โ— : ์ •์  ์ƒ์„ฑ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. getStaticProps๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ๋ฐœ ๋˜๋Š” ๋นŒ๋“œ ํ”„๋กœ์„ธ์Šค ์ค‘์— ์‚ฌ์ „ ์ƒ์„ฑ๋œ ํŽ˜์ด์ง€์ž…๋‹ˆ๋‹ค. 

โ—‹ : ์ •์  ์ฆ‰ ๋ชจ๋“  ํŽ˜์ด์ง€๊ฐ€ ์‚ฌ์ „ ์ƒ์„ฑ๋˜์ง€๋งŒ, ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ getStaticProps๋‚˜ ์ด์™€ ์œ ์‚ฌํ•œ ๊ฒƒ์„ ์“ฐ์ง€ ์•Š์€ ํŽ˜์ด์ง€์ž…๋‹ˆ๋‹ค. 

 

์‚ฌ์ „ ์ƒ์„ฑ๋œ ๋‘ ํŽ˜์ด์ง€๊ฐ€ ์‹œ์ž‘ ํŽ˜์ด์ง€์ด๋ฏ€๋กœ /๋’ค์— ์•„๋ฌด๊ฒƒ๋„ ์—†๋Š” index.js๊ฐ€ ์žˆ๊ณ . 404 ํŽ˜์ด์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ์ž๋™ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. 404 ํŽ˜์ด์ง€์˜ โ—‹ ๋Š” ์•„๋ฌด๋Ÿฐ ๋ฐ์ดํ„ฐ ์—†์ด ์‚ฌ์ „ ์ƒ์„ฑ๋˜์—ˆ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค. index.js๋Š” getStaticProps๋กœ ์ •์  ์‚ฌ์ „ ์ƒ์„ฑ๋˜์—ˆ์œผ๋ฏ€๋กœ โ— ์ด ์žˆ์Šต๋‹ˆ๋‹ค. 

.next ํด๋” ์•ˆ์— server ํด๋”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์‚ฌ์ „ ์ƒ์„ฑ๋œ HTML ํŒŒ์ผ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ด ํŽ˜์ด์ง€๋ฅผ ๋ฐฉ๋ฌธํ•˜๋ฉด ๋ณด์ผ pre-renders ํŽ˜์ด์ง€์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฒ€์ƒ‰ ์—”์ง„ ํฌ๋กค๋Ÿฌ๋‚˜ ํŽ˜์ด์ง€์˜ ๋ฐฉ๋ฌธ์ž์—๊ฒŒ ์ดˆ๊ธฐ ์š”์ฒญ์œผ๋กœ ๋‹ค์‹œ ๋ณด๋‚ด์ง€๋Š” ์‚ฌ์ „ ์ƒ์„ฑ๋œ ํŽ˜์ด์ง€์ž…๋‹ˆ๋‹ค. 

 

์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ํ”„๋กœ๋•์…˜ ์ค€๋น„ ํŽ˜์ด์ง€๋ฅผ ๋ฏธ๋ฆฌ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ํŽ˜์ด์ง€ ํ”„๋กœ๋•์…˜์„ ์œ„ํ•ด ์›๊ฒฉ ์ปดํ“จํ„ฐ๋กœ ์ˆ˜ํ–‰ํ•˜๊ธฐ๋„ ํ•˜์ง€๋งŒ, ๊ฐœ๋ฐœ์ž ์ปดํ“จํ„ฐ๋กœ ๋กœ์ปฌ ์ˆ˜ํ–‰ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. localhost:3000์—์„œ ์‹œ์ž‘ํ•˜์ง€๋งŒ ์ง€๊ธˆ์€ ๊ฐœ๋ฐœ ์„œ๋ฒ„๊ฐ€ ์•„๋‹ˆ๋ผ ํ”„๋กœ๋•์…˜ ์ค€๋น„ ํŽ˜์ด์ง€๋ฅผ ์ œ๊ณตํ•˜๋Š” ์‹ค์ œ ์„œ๋ฒ„์ž…๋‹ˆ๋‹ค. 

โžœ  nextjs-pre-rendering git:(main) npm start

> nextjs-pre-rendering@0.1.0 start
> next start

ready - started server on 0.0.0.0:3000, url: http://localhost:3000

 

94.  Incremental Static Generation (ISR) ํ™œ์šฉํ•˜๊ธฐ

๋งŒ์•ฝ ์ž์ฃผ ๋ฐ”๋€Œ๋Š” ๋ฐ์ดํ„ฐ๋ผ๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”? ์˜ˆ๋กœ ํŽ˜์ด์ง€๊ฐ€ ๋ฐฐํฌ๋œ ํ›„ ๋„ค๋ฒˆ์งธ product๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ ๋นŒ๋“œํ•˜๊ณ  ๋‹ค์‹œ ๋ฐฐํฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 

 

  1. ์ฒซ ๋ฒˆ์งธ ์†”๋ฃจ์…˜์€ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ๋นŒ๋“œํ•˜์ง€๋งŒ, ์„œ๋ฒ„์—์„œ ์—…๋ฐ์ดํŠธ๋œ ๋ฐ์ดํ„ฐ fetching์„ ์œ„ํ•ด useEffect๋ฅผ ์‚ฌ์šฉํ•˜๋Š” React ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. 
  2. ๋‘๋ฒˆ์งธ๋Š” Nexct.js์˜ ISR์„ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŽ˜์ด์ง€๋ฅผ ๋นŒ๋“œํ•  ๋•Œ ์ •์ ์œผ๋กœ ํ•œ ๋ฒˆ๋งŒ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ฐฐํฌ ํ›„์—๋„ ์žฌ๋ฐฐํฌ ์—…์ด ๊ณ„์† ์—…๋ฐ์ดํŠธ ๋œ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค. ์˜ˆ๋กœ 60์ดˆ ๋งˆ๋‹ค์ผ ๊ฒฝ์šฐ, ํŠน์ • ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ์š”์ฒญ์ด ์žˆ๊ณ , ๋งˆ์ง€๋ง‰์œผ๋กœ ์žฌ์ƒ์„ฑ๋œ ํ›„ 60์ดˆ๊ฐ€ ์ง€๋‚˜์ง€ ์•Š์•˜๋‹ค๋ฉด ๊ธฐ์กด ํŽ˜์ด์ง€๊ฐ€ ๋ฐฉ๋ฌธ์ž์—๊ฒŒ ์ œ๊ณต๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‹œ๊ฐ„์€ ์ •ํ•˜๊ธฐ ๋‚˜๋ฆ„์ž…๋‹ˆ๋‹ค. 

 

export async function getStaticProps() {
  console.log("(Re-) Generating...");
  const filePath = path.join(process.cwd(), "data", "dummy-backend.json");
  const jsonData = await fs.readFile(filePath);
  const data = JSON.parse(jsonData);

  return {
    props: {
      products: data.products,
    },
    revalidate: 10,
  };
}

 

revalidate๋ฅผ ์ด์šฉํ•˜์—ฌ Next.js๊ฐ€ ์ด ํŽ˜์ด์ง€๋ฅผ ์žฌ์ƒ์„ฑํ•  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜๋Š” ์‹œ๊ฐ„์„ ์ดˆ ๋‹จ์œ„๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ˆซ์ž๊ฐ€ ๋†’์„์ˆ˜๋ก ์ด ํŽ˜์ด์ง€๊ฐ€ ๋‹ค์‹œ ์ƒ์„ฑ๋˜๋Š” ํšŸ์ˆ˜๋Š” ์ค„์–ด๋“ญ๋‹ˆ๋‹ค. ํ•ญ์ƒ ๋‚ด์šฉ์ด ๋ฐ”๋€Œ๋Š” ๋งค์šฐ ๋™์ ์ธ ํŽ˜์ด์ง€๋Š” 1์ดˆ์™€ ๊ฐ™์ด ๋งค์šฐ ์ž‘์€ ๊ฐ’์„ ๋„ฃ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. dev ํ™˜๊ฒฝ์—๋Š” revalidate ๊ฐ’๊ณผ ์ƒ๊ด€์—†์ด ๋งค๋ฒˆ ํŽ˜์ด์ง€๋ฅผ ์žฌ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. prod ํ™˜๊ฒฝ์—์„œ๋Š” ๊ฐ’์— ๋”ฐ๋ผ ๋ณ€ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. 

 

95. ISR ๋‚ด๋ถ€์—์„œ ์ผ์–ด๋‚˜๋Š” ์ผ

โžœ  nextjs-pre-rendering git:(main) โœ— yarn run build            
yarn run build
yarn run v1.22.11
$ next build
info  - Linting and checking validity of types  
info  - Creating an optimized production build  
info  - Compiled successfully
info  - Collecting page data  
[    ] info  - Generating static pages (0/3)(Re-) Generating...
info  - Generating static pages (3/3)
info  - Finalizing page optimization  

Route (pages)                              Size     First Load JS
โ”Œ โ— / (ISR: 10 Seconds)                    404 B          79.3 kB
โ”œ   /_app                                  0 B            78.9 kB
โ”œ โ—‹ /404                                   212 B          79.1 kB
โ”” λ /api/hello                             0 B            78.9 kB
+ First Load JS shared by all              79.1 kB
  โ”œ chunks/framework-aefaf282dc32bbc7.js   45.7 kB
  โ”œ chunks/main-5cebf592faf0463a.js        31.8 kB
  โ”œ chunks/pages/_app-aba2de2b7ae6fcb3.js  390 B
  โ”œ chunks/webpack-2369ea09e775031e.js     1.02 kB
  โ”” css/49861c0d8668ac82.css               185 B

λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)
โ—‹  (Static)  automatically rendered as static HTML (uses no initial props)
โ—  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)
   (ISR)     incremental static regeneration (uses revalidate in getStaticProps)

ISR: 10์ดˆ๋ฅผ ํ†ตํ•ด 10์ดˆ๋งˆ๋‹ค ์žฌ์ƒ์„ฑ ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Œ์„ ๋œปํ•ฉ๋‹ˆ๋‹ค. ๋น ๋ฅด๊ฒŒ ๋ช‡ ๋ฒˆ์„ ์ƒˆ๋กœ ๊ณ ์นจํ•˜๋ฉด ์•„์ง 10์ดˆ๊ฐ€ ์ง€๋‚˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— (Re-)Generating..์ด ๋‚˜์˜ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. 

 

96. "getStaticProps" ๊ตฌ์„ฑ ์˜ต์…˜ ์‚ดํŽด๋ณด๊ธฐ

nonFound๋ฅผ ture๋กœ ์„ค์ •ํ•˜๋ฉด ํŽ˜์ด์ง€๊ฐ€ 404 ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ ์ผ๋ฐ˜ ํŽ˜์ด์ง€ ๋Œ€์‹ ์— 404 ์˜ค๋ฅ˜ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. ์ด ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” ์–ด๋–ค ์ด์œ ๋กœ๋“  ํŒจ์นญ์— ์‹คํŒจํ•˜๋ฉด, ๊ทธ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ฆ‰ ์ƒํ’ˆ์ด ์—†์„ ๋•Œ๋งŒ notFound๋ฅผ true๋กœ ์„ค์ •ํ•ด์„œ notFound ํŽ˜์ด์ง€๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ํŒจ์น˜๋œ ๋ฐ์ดํ„ฐ์—์„œ ์ƒํ’ˆ์ด ํ•˜๋‚˜๋ผ๋„ ์žˆ์œผ๋ฉด ์ผ๋ฐ˜ ํŽ˜์ด์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. 

  if (data.products.length === 0) {
    return { notFound: true };
  }

 

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

  if (!data) {
    return {
      redirect: {
        destination: "/no-data",
      },
    };
  }

 

์ง€๊ธˆ์€ ์ด ๋‘๊ฐ€์ง€ ์˜ต์…˜์„ ์‚ฌ์šฉํ•  ์ผ์€ ์—†์ง€๋งŒ, ์•Œ๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค :-) 

 

97. ๋™์  ๋งค๊ฐœ๋ณ€์ˆ˜ ์ž‘์—…ํ•˜๊ธฐ

๋ชจ๋“  ์ƒํ’ˆ์—๋Š” ์„ค๋ช…์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ด…์‹œ๋‹ค. ๋ชจ๋“  ์ƒํ’ˆ์€ ํด๋ฆญ ๊ฐ€๋Šฅํ•œ ๋งํฌ๋ผ์„œ ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฑฐ๊ธฐ์„œ ์ƒํ’ˆ ์„ค๋ช…์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ƒํ’ˆ ์ƒ์„ธ ํŽ˜์ด์ง€๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  (pid[].js)  ๋Œ€๊ด„ํ˜ธ๊ฐ€ ์žˆ๋Š” ๋™์  ์„ธ๊ทธ๋จผํŠธ๋ฅผ ๋งŒ๋“ค๋ฉด ๋ฉ๋‹ˆ๋‹ค. React์—์„œ ์ž„ํฌํŠธํ•œ useEffect๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ด ์ƒํ’ˆ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•  ์„œ๋ฒ„์— HTTP ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์ง€๋งŒ ํŽ˜์ด์ง€๊ฐ€ ์ฒ˜์Œ ๋ Œ๋”๋ง ๋˜์–ด ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ด ๋ด…์‹œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๊ฒ€์ƒ‰ ์—”์ง„์ด ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ async ํ”„๋กœํผํ‹ฐ ํ•จ์ˆ˜๋ฅผ ๋‹ค์‹œ ์‚ฌ์šฉํ•  ๊ฒ๋‹ˆ๋‹ค.

export async function getStaticProps()

ํŒŒ์ผ ์ „์ฒด๋ฅผ ์ฝ๊ณ  ๋ชจ๋“  ์ƒํ’ˆ์„ ๋ฐ˜ํ™˜ํ•˜๊ธฐ๋ณด๋‹ค ํŒŒ์ผ์„ ์ฝ๊ณ  ๊ฑฐ๊ธฐ์„œ ํ•˜๋‚˜์˜ ์ƒํ’ˆ๋งŒ ๋ฐ˜ํ™˜ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‹น์—ฐํžˆ ์–ด๋–ค ์ƒํ’ˆ์ด ์—ฌ๊ธฐ์— ๋ฐ˜ํ™˜๋ ์ง€ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ ์ƒํ’ˆ์„ ๊ฒฐ์ •ํ•˜๊ธฐ ์œ„ํ•ด์„œ URL์— ์žˆ๋Š” ๊ตฌ์ฒด์ ์ธ ๊ฐ’์„ ์‚ดํŽด๋ณด์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰ pid ํ‚ค์— ๋Œ€ํ•œ ๊ตฌ์ฒด์ ์ธ ๊ฐ’์ด ๋˜๊ฒ ์ง€์š”. ์ด๋•Œ ์ฝ˜ํ…์ŠคํŠธ(context) ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋‹ค์‹œ ์ค‘์š”ํ•ด์ง‘๋‹ˆ๋‹ค. ์•ž์„œ ์ž ์‹œ ์–ธ๊ธ‰ํ–ˆ์ง€๋งŒ NextJS์— ์˜ํ•œ ์ฝ˜ํ…์ŠคํŠธ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌ์ฒด์ ์ธ ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐ’์„ ๊ตฌํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ฆ‰ ๊ฒฝ๋กœ์ƒ์˜ ๋™์  ์„ธ๊ทธ๋จผํŠธ์— ๋Œ€ํ•œ ๊ตฌ์ฒด์ ์ธ ๊ฐ’์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ๊ฐ’์— ์•ก์„ธ์Šคํ•˜๊ธฐ ์œ„ํ•ด context์˜ params ํ‚ค๋ฅผ ๋ด…์‹œ๋‹ค.  NextJS๊ฐ€ ์ œ๊ณตํ•˜๋Š” context ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  params(๋งค๊ฐœ๋ณ€์ˆ˜)๋Š” ํ‚ค-๊ฐ’ ์Œ์ด ์žˆ๋Š” ๊ฐ์ฒด์ด๋ฉฐ ์ด๋•Œ ํ‚ค์˜ ์‹๋ณ„์ž๋Š” ๋™์  ๊ฒฝ๋กœ ์„ธ๊ทธ๋จผํŠธ์ž…๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—๋Š” [pid]๊ฐ€ ๋  ๊ฒ๋‹ˆ๋‹ค. ํŽ˜์ด์ง€์˜ ์œ ์ผํ•œ ๋™์  ๋งค๊ฐœ๋ณ€์ˆ˜ ์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜์˜ useRouter ํ›…์„ ํ†ตํ•ด ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ•์˜ ๊ณผ์ •์˜ ์•ž๋ถ€๋ถ„์—์„œ ๋‹ค๋ฃจ์—ˆ์–ด์š”. userRouter ํ›…์„ ์‚ฌ์šฉํ•ด์„œ router ๊ฐ์ฒด์— ์•ก์„ธ์Šคํ–ˆ๊ณ  router.query๋กœ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ถ”์ถœํ–ˆ์Šต๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜์™€ getStaticProps()์—์„œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ถ”์ถœํ•  ๋•Œ ์ฐจ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜์—์„œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ถ”์ถœํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ถ”์ถœ๋œ ID๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์ผ๋ถ€ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ด ๊ฑฐ๊ธฐ์—์„œ ํŽ˜์นญํ•˜๊ธฐ ์œ„ํ•ด์„œ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๊ณผ์ •์€ ๋ธŒ๋ผ์šฐ์ €์—์„œ๋งŒ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.

getStaticProps()๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•˜์—ฌ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ๋ Œ๋”๋งํ•˜๊ฒŒ ๋˜๋ฉด ์ด ๊ฒฝ์šฐ๋Š” ์„œ๋ฒ„์—์„œ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  getStaticProps๋Š” ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜๋ณด๋‹ค ๋จผ์ € ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ๋ Œ๋”๋งํ•˜๊ธฐ ์œ„ํ•ด ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฏ€๋กœ ์„œ๋ฒ„์ƒ์—์„œ ํ˜น์€ getStaticProps๋กœ ๊ตฌ์ถ• ๊ณผ์ • ์ค‘์— ํŽ˜์ด์ง€๋ฅผ ๋ฏธ๋ฆฌ ์ค€๋น„ํ•˜๋ ค๋ฉด ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ์˜ ์•ก์„ธ์Šค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰ getStaticProps ๋‚ด๋ถ€์˜ ๋™์  ๊ฒฝ๋กœ ์„ธ๊ทธ๋จผํŠธ์— ์•ก์„ธ์Šคํ•ด์„œ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ†ตํ•ด ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ ์•ˆ์—๋„ ๋™์  ์„ธ๊ทธ๋จผํŠธ๊ฐ€ ํ•„์š”ํ•œ ๊ฒŒ ์•„๋‹ˆ๋ฉด ์ถ”์ถœํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿฌ๋‚˜ ๋ฐ์ดํ„ฐ ์‚ฌ์ „ ์ค€๋น„๋Š” getStaticProps์—์„œ ํ•ด์•ผ ํ•˜๋ฉฐ dummy-backend.json ํŒŒ์ผ์— ์ ‘๊ทผํ•ด์„œ ํ•ด๋‹นํ•˜๋Š” ID๋กœ ์ƒํ’ˆ์„ ์ฝ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์‹œ ๊ฐ์ฒด ๊ตฌ์กฐ ๋ถ„ํ•ด๋กœ loadedProduct๋ฅผ ์ถ”์ถœํ•˜๋Š”๋ฐ props์—์„œ ์–ป์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์—ฌ๊ธฐ๋„ props๋ฅผ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ƒํ’ˆ ์ด๋ฆ„์„ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” loadedProduct.title ๋˜ํ•œ ์ƒํ’ˆ ์„ค๋ช… ์—ญ์‹œ loadProduct.description์ž…๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋ด…์‹œ๋‹ค. index.js ํŒŒ์ผ์„ ๋งํฌ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ˆ˜์ •ํ•ฉ์‹œ๋‹ค. ๋งํฌ๋ฅผ ํด๋ฆญํ–ˆ๋”๋‹ˆ ์—๋Ÿฌ๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค. 'getStaticPaths is required'

 

URL์— ์ธ์ฝ”๋”ฉ๋œ ๊ตฌ์ฒด์ ์ธ ๊ฐ’์— ์•ก์„ธ์Šคํ•˜๋ ค๊ณ  params๋ฅผ ์‚ฌ์šฉํ–ˆ์œผ๋ฉฐ ๊ทธ๋ ‡๊ฒŒ ์ถ”์ถœ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ •ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ํŽ˜์นญํ•˜๊ณ  ์ปดํฌ๋„ŒํŠธ์— ํ™œ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ์™œ ์ด๋Ÿฐ ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

98. ๋™์  ํŽ˜์ด์ง€๋ฅผ ์œ„ํ•œ "getStaticPaths" ๊ฐœ์š”

export default function HomePage(props) {
  const { products } = props;

  return (
    <ul>
      {products.map((product) => (
        <li key={product.id}>
          <Link href={`/${product.id}`}>{product.title}</Link>
        </li>
      ))}
    </ul>
  );
}
export default function ProductDetailPage() {
  const { loadedProduct } = props;
  return (
    <Fragment>
      <h1>{loadedProduct.title}</h1>
      <p>{loadedProduct.description}</p>
    </Fragment>
  );
}

export async function getStaticProps(context) {
  const { params } = context;

  const productId = params.pid;

  const filePath = path.join(process.cwd(), "data", "dummy-backend.json");
  const jsonData = await fs.readFile(filePath);
  const data = JSON.parse(jsonData);

  const product = data.products.find((product) => product.id === productId);
  return {
    props: {
      loadedProduct: product,
    },
  };
}


NextJS๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ์ƒ์„ฑํ•˜์ง€๋งŒ, ๋™์  ํŽ˜์ด์ง€์—์„œ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฆ‰ ์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„์— ๋Œ€๊ด„ํ˜ธ๊ฐ€ ์žˆ์„ ๋•Œ์ธ๋ฐ์š”. ํ•ด๋‹น ํŽ˜์ด์ง€๋กœ ์—ฐ๊ฒฐ๋˜๋Š” ๋™์  ์„ธ๊ทธ๋จผํŠธ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๊ธฐ๋ณธ ๋™์ž‘์œผ๋กœ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ์ƒ์„ฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. 

์™œ ๊ธฐ๋ณธ๊ฐ’์ด ์•„๋‹๊นŒ์š”? ์ด ํŽ˜์ด์ง€๋Š” ํ•˜๋‚˜๊ฐ€ ์•„๋‹ˆ๋ผ ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€๋กœ ์ด๋ฃจ์–ด์ง€ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ƒํ’ˆ ID๋งˆ๋‹ค ์„œ๋กœ ๋‹ค๋ฅธ ํŽ˜์ด์ง€์— ํ”„๋ ˆ์ž„ ๋ฐ HTML ์ฝ˜ํ…์ธ ๋Š” ๊ฐ™๊ณ  ๋ฐ์ดํ„ฐ๋งŒ ๋‹ค๋ฅด๊ฒŒ ๊ตฌ์„ฑ๋˜๋Š” ๊ฒ๋‹ˆ๋‹ค. ์ด ํŽ˜์ด์ง€๋Š” p1๋‚˜ p2 p1000๋กœ๋„ ๋กœ๋“œ๋  ์ˆ˜ ์žˆ๋Š”๋ฐ NextJS๋Š” ์‚ฌ์ „์— ๋™์  ํŽ˜์ด์ง€๋ฅผ ์œ„ํ•ด์„œ ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ํŽ˜์ด์ง€๋ฅผ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๋™์  ํŽ˜์ด์ง€๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์‚ฌ์ „ ์ƒ์„ฑ๋˜์ง€ ๋ชปํ•˜๊ณ  ๋Œ€์‹  ์„œ๋ฒ„์—์„œ ํ•ญ์ƒ ๊ทธ๋•Œ ๊ทธ๋•Œ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. 

๊ทธ๋ž˜์„œ ์ด์ „์—๋Š” ์ž‘๋™ํ–ˆ์ง€๋งŒ ํ˜„์žฌ getStaticProps๋ฅผ ์ถ”๊ฐ€ํ•œ ์ƒํƒœ๋ผ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  page ์ปดํฌ๋„ŒํŠธ ํŒŒ์ผ์— ์ด ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์‚ฌ์ „์— ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•˜๋„๋ก NextJS์— ์š”์ฒญํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. index.js์—์„œ๋Š” ์ฐจ์ด๊ฐ€ ์—†์—ˆ์ฃ  ์–ด์จŒ๋“  ๊ธฐ๋ณธ๊ฐ’์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋™์  ํŽ˜์ด์ง€์—๋Š” ์ฐจ์ด์ ์ด ์ƒ๊น๋‹ˆ๋‹ค. ์•ž์„œ ์ด์•ผ๊ธฐํ•œ ์ด์œ  ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ๊ฐ’์ด ์•„๋‹ˆ๋ผ์„œ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค.

NextJS๋Š” ์–ผ๋งˆ๋‚˜ ๋˜๋Š” ํŽ˜์ด์ง€๊ฐ€ ํ•„์š”ํ•œ์ง€ ์•Œ ์ˆ˜ ์—†๊ณ  ์šฐ๋ฆฌ์—๊ฒŒ ์–ด๋–ค ๋™์  ์„ธ๊ทธ๋จผํŠธ์˜ ๊ตฌ์ฒด์ ์ธ ๊ฐ’์ด ํ•„์š”ํ•œ์ง€ ๋ชจ๋ฆ…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋™์  ๋ผ์šฐํŠธ์˜ ๊ฒฝ์šฐ NextJS๊ฐ€ ๋” ๋งŽ์€ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์šฐ๋ฆฌ๋Š” NextJS์— ์–ด๋–ค ๊ฒฝ๋กœ๊ฐ€ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•˜๋Š”์ง€ ๋™์  ํŽ˜์ด์ง€์—์„œ ์–ด๋–ค ์ธ์Šคํ„ด์Šค๊ฐ€ ์‚ฌ์ „ ์ƒ์„ฑ๋ผ์•ผ ํ•˜๋Š”์ง€ ์•Œ๋ ค์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. NextJS์— ์•Œ๋ ค์ฃผ๋ ค๋ฉด ํŽ˜์ด์ง€์— ์ถ”๊ฐ€ํ•  ๋‹ค๋ฅธ ํ•จ์ˆ˜, ์ฆ‰ ํŽ˜์ด์ง€ ํŒŒ์ผ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ๋˜ ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒŒ ๋ฐ”๋กœ ๋น„๋™๊ธฐ ํ•จ์ˆ˜์ธ getStaticPaths()์ž…๋‹ˆ๋‹ค. await ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ  getStaticProps()์ฒ˜๋Ÿผ page ์ปดํฌ๋„ŒํŠธ ํŒŒ์ผ์—๋งŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

 

99. getStaticPaths ์‚ฌ์šฉํ•˜๊ธฐ

getStaticPaths()๋Š” ๋™์  ํŽ˜์ด์ง€์˜ ์–ด๋–ค ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ• ์ง€ NextJS์— ์•Œ๋ ค์ค๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ getStaticProps()์ฒ˜๋Ÿผ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜์ง€๋งŒ ๊ฐ์ฒด์˜ ๊ฐ’์€ ์„œ๋กœ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. paths ํ‚ค๊ฐ€ ์žˆ๋Š” ๊ฐ์ฒด์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.์ฆ‰ ๊ฐ์ฒด๋ฅผ ๊ฐ€์ง„ ๋ฐฐ์—ด์ด ๋ฉ๋‹ˆ๋‹ค. ์ด ๊ฐ์ฒด์— params ํ‚ค๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋ฉฐ, params๋Š” ์—ฌ๋Ÿฌ ํ‚ค-๊ฐ’ ์Œ์ด ์žˆ๋Š” ๋˜ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๊ณ  ์ด๋•Œ, ํ‚ค๋Š” ์ด ํŽ˜์ด์ง€๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฐ๊ฐ์˜ ๋™์  ์„ธ๊ทธ๋จผํŠธ ์‹๋ณ„์ž์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ํด๋”๊ฐ€ ์ค‘์ฒฉ๋˜์–ด ํด๋” ์ด๋ฆ„๋„ ๋™์ ์ด๋ผ๋ฉด ์—ฌ๋Ÿฌ ์‹๋ณ„์ž๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ ์—ฌ๊ธฐ์„œ๋Š” pid ํ•˜๋‚˜๋ฟ์ž…๋‹ˆ๋‹ค. ๊ทธ ๊ฐ’์€ ํŽ˜์ด์ง€๊ฐ€ ์ƒ์„ฑ๋˜๊ธฐ ์œ„ํ•œ ๊ตฌ์ฒด์ ์ธ ๊ฐ’์ž…๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค๋ฉด ์ด ํŽ˜์ด์ง€๋ฅผ ์„ธ ๋ฒˆ ์ƒ์„ฑํ•˜๋Š”๋ฐ ์ด ๋™์  ํŽ˜์ด์ง€ ์‹๋ณ„์ž์˜ ๊ฐ’์€ p1, p2, p3์ด ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ pid๋ฅผ p1์œผ๋กœ ์„ค์ •ํ•˜๊ณ  ๋ฐ˜๋ณตํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋˜ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ params๋ฅผ ๋˜ ๋‹ค๋ฅธ ๊ฐ์ฒด์ธ pid: 'p2'๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์„ธ ๋ฒˆ์งธ๋กœ ๋ฐ˜๋ณตํ• ๊ฒŒ์š”. ์ด ๊ฐ์ฒด์—์„œ๋Š” params๋ฅผ p3๋กœ ์„ค์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋™์  ํŽ˜์ด์ง€๊ฐ€ ์„ธ ๋ฒˆ ์‚ฌ์ „ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•˜๋ฉฐ ์„ธ ๊ฐ€์ง€ ๊ฐ’์„ ๊ฐ€์ง„๋‹ค๋Š” ์‚ฌ์‹ค์„ NextJS์— ์•Œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. NextJS๊ฐ€ ๊ฐ ID์— ๋Œ€ํ•ด getStaticProps()๋ฅผ ์„ธ ๋ฒˆ ํ˜ธ์ถœํ•˜๊ณ  ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ด ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ์ฒ˜๋Ÿผ ํ•ด๋‹น ID๋ฅผ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒŒ ์ž‘๋™ํ•˜๋ ค๋ฉด paths ๋‹ค์Œ์— ๋‹ค๋ฅธ fallback ํ‚ค๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ๋‹ค์‹œ ๋‹ค๋ฃจ๊ฒ ์ง€๋งŒ ์ง€๊ธˆ์€ false๋กœ ๋‘๊ฒ ์Šต๋‹ˆ๋‹ค. NextJS๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์‚ฌ์ „ ์ƒ์„ฑํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ •ํ™•ํ•œ ํŽ˜์ด์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. getStaticPaths()๋Š” ๋™์  ํŽ˜์ด์ง€์˜ ์–ด๋–ค ๊ตฌ์ฒด์ ์ธ ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์ „ ์ƒ์„ฑํ• ์ง€ ์•Œ๋ ค์ฃผ๋Š” ํ•จ์ˆ˜๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

 

100. "getStaticPaths" & Link Prefetching: Behind The Scenes

yarn build ๋ช…๋ น์„ ์‹คํ–‰ํ•ด์„œ ํ”„๋กœ๋•์…˜์šฉ์œผ๋กœ ๊ตฌ์ถ•ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

โžœ  nextjs-pre-rendering git:(main) yarn build
yarn run v1.22.17
$ next build
info  - Linting and checking validity of types  
info  - Creating an optimized production build  
info  - Compiled successfully
info  - Collecting page data  
[    ] info  - Generating static pages (0/6)(Re-) Generating...
info  - Generating static pages (6/6)
info  - Finalizing page optimization  

Route (pages)                              Size     First Load JS
โ”Œ โ— / (ISR: 10 Seconds)                    2.84 kB        81.7 kB
โ”œ   /_app                                  0 B            78.9 kB
โ”œ โ— /[pid] (619 ms)                        449 B          79.4 kB
โ”œ   โ”œ /p1
โ”œ   โ”œ /p2
โ”œ   โ”” /p3
โ”œ โ—‹ /404                                   212 B          79.1 kB
โ”” λ /api/hello                             0 B            78.9 kB
+ First Load JS shared by all              79.1 kB
  โ”œ chunks/framework-0f397528c01bc177.js   45.7 kB
  โ”œ chunks/main-5cebf592faf0463a.js        31.8 kB
  โ”œ chunks/pages/_app-aba2de2b7ae6fcb3.js  390 B
  โ”œ chunks/webpack-2369ea09e775031e.js     1.02 kB
  โ”” css/49861c0d8668ac82.css               185 B

λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)
โ—‹  (Static)  automatically rendered as static HTML (uses no initial props)
โ—  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)
   (ISR)     incremental static regeneration (uses revalidate in getStaticProps)

 ๋ช‡๋ช‡ ํŽ˜์ด์ง€๊ฐ€ ์‚ฌ์ „ ๋ Œ๋”๋ง ๋˜์—ˆ๊ณ  ์ตœ์ข…์ ์œผ๋กœ 5ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ์Šฌ๋ž˜์‹œ๋งŒ ์žˆ๋Š” ํŽ˜์ด์ง€์ธ ์‹œ์ž‘ ํŽ˜์ด์ง€๋ฅผ ๋ด…์‹œ๋‹ค. ๋ฐ”๋กœ index.js ํŒŒ์ผ์ธ๋ฐ ์œ ํšจ์„ฑ ์žฌ๊ฒ€์‚ฌ ์‹œ๊ฐ„์ด 10์ดˆ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ๋™์  ํŽ˜์ด์ง€๋Š” ์„ธ ๊ฐ€์ง€ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ–ˆ์–ด์š”. ๊ฐ๊ฐ p1, p2, p3์ž…๋‹ˆ๋‹ค ์—ฌ๋Ÿฌ๋ถ„๋„ ์•„์‹œ๋‹ค์‹œํ”ผ getStaticPaths()์—์„œ ๋ฐ˜ํ™˜๋œ ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ์ด์ฃ . ๋˜ํ•œ 404 ํŽ˜์ด์ง€ ์—ญ์‹œ ์ด์ „์ฒ˜๋Ÿผ ์‚ฌ์ „ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

server์˜ pages๋กœ ๊ฐ€๋ฉด ๋‹ค์–‘ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜์— ๋Œ€ํ•œ HTML ํŒŒ์ผ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋งํฌ๋ฅผ ํ†ตํ•ด ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์ „ ๋กœ๋”ฉํ•˜๋Š” JSON ํŒŒ์ผ๋„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰ ์ดˆ๊ธฐ ํŽ˜์ด์ง€ ๋กœ๋”ฉ ๋•Œ๊ฐ€ ์•„๋‹Œ ์šฐ๋ฆฌ๊ฐ€ ๊ทธ ํŽ˜์ด์ง€์— ์žˆ์„ ๋•Œ์ž…๋‹ˆ๋‹ค. HTML ํŒŒ์ผ์„ ์‚ดํŽด๋ณด๋ฉด ๊ฒฐ๊ตญ ์—ฌ๊ธฐ ์–ด๋”˜๊ฐ€์—์„œ Product 1์˜ ํ…์ŠคํŠธ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์ „ ํŽ˜์นญํ•˜๋Š” ๊ฒƒ๋„ ๋ณด์—ฌ๋“œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. npm start๋ฅผ ์‹คํ–‰ํ•ด๋ด…์‹œ๋‹ค.

โžœ  nextjs-pre-rendering git:(main) โœ— npm start

> nextjs-pre-rendering@0.1.0 start
> next start

ready - started server on 0.0.0.0:3000, url: http://localhost:3000
(Re-) Generating...
(Re-) Generating...
(Re-) Generating...

๋กœ์ปฌ ๋จธ์‹ ์—์„œ ํ•ด๋‹น ๋นŒ๋“œ ํ”„๋กœ์ ํŠธ๋กœ ํ”„๋กœ๋•์…˜ ์„œ๋ฒ„๋ฅผ ์‹œ์ž‘ํ•ฉ์‹œ๋‹ค. ์ƒˆ๋กœ ๊ณ ์นจํ•˜๋ฉด ํด๋ฆญ ๊ฐ€๋Šฅํ•œ ๋งํฌ๊ฐ€ ๋‚˜์˜ต๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๋ฅผ ์—ด๊ณ  Network ํƒญ์œผ๋กœ ๊ฐ€์„œ localhost: 3000์„ ์ƒˆ๋กœ ๊ณ ์นจํ•˜๋ฉด ํฅ๋ฏธ๋กœ์šด ๊ฒŒ ๋ณด์ด๋Š”๋ฐ์š”,

p1.json, p2.json ๋ฐ p3.json์— ๋Œ€ํ•œ ์š”์ฒญ์ด ์žˆ์Šต๋‹ˆ๋‹ค.  ๋งํฌ๋ฅผ ํด๋ฆญํ•˜๋ฉด ์ƒˆ๋กœ ๊ณ ์นจ ๋  ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ํ”„๋กœํผํ‹ฐ๊ฐ€ pre-fetching ๋˜์—ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์šฐ์Šค๋ฅผ ๋งํฌ์— ๊ฐ€์ ธ๊ฐ€๊ธฐ๋„ ์ „์— ๋ฐ์ดํ„ฐ๊ฐ€ pre-fetching ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ ํŽ˜์ด์ง€์— ๋“ค์–ด์˜จ ์ƒํƒœ๋‹ˆ๊นŒ์š”. ๋ฐ์ดํ„ฐ๊ฐ€ pre-fetching ๋˜๋Š” ์ •ํ™•ํ•œ ์‹œ์ ์€ NextJS๊ฐ€ ๊ฒฐ์ •ํ•˜๊ณ  ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ค‘์š”ํ•œ ๊ฑด NextJS๊ฐ€ pre-fetching ์„ ํ•ด์ค€๋‹ค๋Š” ๊ฑฐ์ฃ . ์ด์ œ ๋งํฌ๋ฅผ ํด๋ฆญํ•˜๋ฉด ์„œ๋ฒ„์— ์ƒˆ๋กœ์šด ์š”์ฒญ์„ ๋ณด๋‚ด์„œ ์‚ฌ์ „ ๋ Œ๋”๋ง ๋œ HTML ํŒŒ์ผ์„ ๋กœ๋“œํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ์‹ฑ๊ธ€ ํŽ˜์ด์ง€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๊ณ„์† ๋จธ๋ฌด๋ฆ…๋‹ˆ๋‹ค.

 

์ดˆ๊ธฐ ์š”์ฒญ ์ดํ›„, ๋กœ๋“œํ•˜๊ณ  ์ˆ˜ํ™”(hydrate)ํ•˜๋Š” React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์žˆ๊ณ , ๊ทธ๋Ÿฌ๊ณ  ๋‚˜์„œ NextJS๊ฐ€ ์—†๋Š” ์ผ๋ฐ˜ React ์•ฑ์—์„œ์ฒ˜๋Ÿผ JavaScript๊ฐ€ ์ƒˆ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. ์ด ํŽ˜์ด์ง€์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ณณ์€ ๋ฏธ๋ฆฌ fetching ๋œ JSON ํŒŒ์ผ์ธ๋ฐ ์šฐ๋ฆฌ ๋Œ€์‹  ๋กœ๋”ฉํ•˜๊ณ  ์ฝ๊ธฐ๋ฅผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์šฐ๋ฆฌ๊ฐ€ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•œ ํ›„ ๋ฐ์ดํ„ฐ๋ฅผ ํŽ˜์นญํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ตœ์ข…์ ์ธ Product 1 ํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ํƒ์ƒ‰ํ•  ๋•Œ ๋ฐ์ดํ„ฐ๋Š” ์ด๋ฏธ ํ›จ์”ฌ ๋น ๋ฅด๊ฒŒ  ์กด์žฌํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. 

 

 

101. ๋Œ€์ฒด ํŽ˜์ด์ง€ ์ž‘์—…ํ•˜๊ธฐ


fallback ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‚ฌ์ „ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•  ํŽ˜์ด์ง€๊ฐ€ ๋งŽ์„ ๋•Œ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ๋Š” ๋”๋ฏธ ์ƒํ’ˆ์ด ์„ธ ๊ฐœ๋ฐ–์— ์—†์Šต๋‹ˆ๋‹ค. Amazon์ฒ˜๋Ÿผ ์ƒํ’ˆ์ด ์ˆ˜๋ฐฑ๋งŒ ๊ฐœ์ธ ์›น ์‚ฌ์ดํŠธ๋ฅผ ์ƒ์ƒํ•ด ๋ณด์„ธ์š”. ๋ชจ๋“  ์ƒํ’ˆ์„ ์‚ฌ์ „ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ๋ฌผ๋ก  ์ตœ์ ์˜ ๋ฐฉ๋ฒ•์€ ์•„๋‹™๋‹ˆ๋‹ค. ๋‹ค๋งŒ ๋งŽ์€ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ์ƒ์„ฑํ•˜๋ฉด ์‹œ๊ฐ„์ด ๋„ˆ๋ฌด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์ด์ฃ . ๊ทธ๋ฆฌ๊ณ  ์ด๋Ÿฐ ๊ฒฝ์šฐ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐฉ๋ฌธ๊ฐ์ด ๊ฑฐ์˜ ์—†์„ ๊ฒฝ์šฐ ์ˆ˜๋ฐฑ ๊ฐœ์˜ ๊ฒŒ์‹œ๋ฌผ์ด ์žˆ๋Š” ๋ธ”๋กœ๊ทธ๋ฅผ ๋งŒ๋“ค๋ฉด, ๊ทธ์ค‘ ํ•œ ๋ฒˆ๋„ ์ฝํžˆ์ง€ ์•Š๋Š” ๊ฒŒ์‹œ๋ฌผ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐฉ๋ฌธ๊ฐ์ด ๊ฑฐ์˜ ์—†๋Š” ํŽ˜์ด์ง€์˜ ์‚ฌ์ „ ์ƒ์„ฑ์€ ์‹œ๊ฐ„๊ณผ ์ž์› ๋‚ญ๋น„์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ํด๋ฐฑ(fallback) ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ๋ฐ, true๋กœ ์„ค์ •ํ•˜๊ณ  ์˜ˆ๋ฅผ ๋“ค์–ด ์ผ๋ถ€ ํŽ˜์ด์ง€๋งŒ ์‚ฌ์ „ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ƒํ’ˆ ID๊ฐ€ 1์ธ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ๋ Œ๋”๋งํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด ๋ด…์‹œ๋‹ค. ์ฆ‰ p1์€ ์ž์ฃผ ์‚ฌ์šฉ๋˜๊ณ  ๋ฐฉ๋ฌธ๊ฐ์ด ๋งŽ์€ ํŽ˜์ด์ง€๋ผ๊ณ  ์ƒ๊ฐํ•ด ๋ณด์ฃ . ํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ๋‘ ํŽ˜์ด์ง€๋Š” ์‚ฌ์ „ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๋‹ค.


fallback: true 
Product 3์„ ํด๋ฆญํ•˜๋ฉด ์•„์ง ํŽ˜์ด์ง€๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋กœ๋”ฉ๋ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ paths์— ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•„๋„ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. fallback: true๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—ฌ๊ธฐ์— ํฌํ•จ๋˜์ง€ ์•Š์€ ํŽ˜์ด์ง€๋ผ๋„ ์ฆ‰ pid ๋งค๊ฐœ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐ’์ด ์—†๋”๋ผ๋„ ํŽ˜์ด์ง€ ๋ฐฉ๋ฌธ ์‹œ ๋กœ๋”ฉ๋˜๋Š” ๊ฐ’์ด ์œ ํšจํ•  ์ˆ˜ ์žˆ๋„๋ก NextJS์— ์š”์ฒญํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์‚ฌ์ „์— ์ƒ์„ฑ๋˜๋Š” ๊ฑด ์•„๋‹ˆ๊ณ  ์š”์ฒญ์ด ์„œ๋ฒ„์— ๋„๋‹ฌํ•˜๋Š” ์ˆœ๊ฐ„ ์‹œ์ ์— ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์‹์œผ๋กœ ๋ฐฉ๋ฌธ์œจ์ด ๋†’์€ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋ฉฐ ๋ฐฉ๋ฌธ์ด ์ ์€ ํŽ˜์ด์ง€๋ฅผ ์„œ๋ฒ„์— ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์„ ๋ฏธ๋ค„์„œ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์ „ ์ƒ์„ฑ๋˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


ํ•˜์ง€๋งŒ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š”๋ฐ์š”..! ๋งํฌ๋ฅผ ํด๋ฆญํ•˜์ง€ ์•Š๊ณ  ์ง์ ‘ URL์— ์ง์ ‘ ์ž…๋ ฅํ•˜์—ฌ ์ด ํŽ˜์ด์ง€์— ์ƒˆ๋กœ์šด ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.


์—๋Ÿฌ์˜ ์ด์œ ๋Š” ๋™์  ์‚ฌ์ „ ์ƒ์„ฑ ๊ธฐ๋Šฅ์ด ์ฆ‰์‹œ ๋๋‚˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ fallback ๊ธฐ๋Šฅ์„ ์“ฐ๋ ค๋ฉด ์ปดํฌ๋„ŒํŠธ์—์„œ ํด๋ฐฑ ์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค. if (!loadedProduct)๋กœ ์‚ฌ์ „ ์ƒ์„ฑํ•  ๋ถ€๋ถ„์ด ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ๋งŒ์•ฝ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด Loading... ๊ฐ™์€ ๋‚ด์šฉ์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋งŒ๋“ค๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜์— ์ด๋ ‡๊ฒŒ ์ถ”๊ฐ€ํ•˜๊ณ  ์ „๋ถ€ ์ €์žฅํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์ƒˆ๋กœ ๊ณ ์นจํ•˜๋ฉด ์งง๊ฒŒ Loading์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ๋กœ๋”ฉ์ด ์™„๋ฃŒ๋˜๋ฉด NextJS๊ฐ€ ์ž๋™์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์€ useEffect์™€ setState๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ‘œ์ค€ React ์†”๋ฃจ์…˜๊ณผ ๋น„์Šทํ•˜์ง€๋งŒ ๊ฐ„๋‹จํ•˜์ฃ .

๋‹จ์ง€ ํ”„๋กœํผํ‹ฐ๋ฅผ ํ†ตํ•ด ์–ป๊ณ  if()๋กœ ์กด์žฌ๋ฅผ ํ™•์ธํ•ด์„œ ์—†๋Š” ๊ฒฝ์šฐ์—๋Š” ํด๋ฐฑ ์ฝ˜ํ…์ธ ๊ฐ€ ๋‚˜์˜ค๊ฒŒ ํ•˜๋ฉด ๋˜๋Š” ๊ฑฐ์ฃ . ์กด์žฌํ•  ๊ฒฝ์šฐ NextJS๊ฐ€ ์ž๋™์œผ๋กœ ์ปดํฌ๋„ŒํŠธ ํŽ˜์ด์ง€๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ์ผ๋ฐ˜ ์ฝ˜ํ…์ธ ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ ๊ณ ์นจํ•˜๋ฉด ๊ฒฐ๊ตญ ์„ฑ๊ณต์ ์œผ๋กœ ๋กœ๋”ฉ์ด ๋ฉ๋‹ˆ๋‹ค ํด๋ฐฑ ๊ธฐ๋Šฅ ๋•๋ถ„์ด์ฃ .

 

fallback: blocking
ํด๋ฐฑ์„ true๋‚˜ false๋กœ ์„ค์ •ํ•˜์ง€ ์•Š๋Š” ๋Œ€์‹  blocking ๋ฌธ์ž์—ด ๊ฐ’์œผ๋กœ ์„ค์ •ํ•  ๊ฒฝ์šฐ ์ปดํฌ๋„ŒํŠธ์—์„œ ํด๋ฐฑ ํ™•์ธ์„ ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ํŽ˜์ด์ง€ ๋ฐฉ๋ฌธ์ž๊ฐ€ ์‘๋‹ต๋ฐ›๋Š” ์‹œ๊ฐ„์€ ๊ธธ์–ด์ง€์ง€๋งŒ ์ˆ˜์‹ ๋œ ์‘๋‹ต์€ ์ข…๋ฃŒ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ๋‹ค์‹œ ์ƒˆ๋กœ ๊ณ ์นจํ•ด๋„ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ๋ฟ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ํ•„์š”ํ•œ ์ ‘๊ทผ ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ๋ถ„์˜ ์„ ํƒ์— ๋‹ฌ๋ ค์žˆ์Šต๋‹ˆ๋‹ค. ๋น ๋ฅด๊ฒŒ ๋ฌด์—‡์ธ๊ฐ€๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒŒ ๋” ์ค‘์š”ํ•  ๋•Œ๊ฐ€ ์žˆ์ฃ . ํŽ˜์ด์ง€ ์ƒ์„ฑ๊ณผ ๋ฐ์ดํ„ฐ ํŽ˜์นญ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆด ๊ฒฝ์šฐ ํŠนํžˆ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ blocking๊ณผ ๊ฐ™์€ ๋ฌธ์ž์—ด์ด ๋‚˜์„ ์ˆ˜๋„ ์žˆ์–ด์š”. ์ด๋ ‡๊ฒŒ ๋งค์šฐ ๊ฐ„๋‹จํ•œ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ๋“œ๋ ธ์Šต๋‹ˆ๋‹ค.

 

 

102. ๋™์ ์œผ๋กœ ๊ฒฝ๋กœ ๋กœ๋”ฉํ•˜๊ธฐ 

getStaticPaths ํ•จ์ˆ˜์˜ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ดค์ง€๋งŒ ์ด๋Œ€๋กœ ์‹ค์ œ ์ž‘์—…์— ์ ์šฉํ•˜๊ธฐ๋Š” ๋ฌด๋ฆฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด pid ๊ฐ’์„ ํ•˜๋“œ ์ฝ”๋”ฉํ–ˆ์œผ๋‹ˆ๊นŒ์š”. async function getData๋ฅผ ์ž‘์„ฑํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. 

async function getData() {
  const filePath = path.join(process.cwd(), "data", "dummy-backend.json");
  const jsonData = await fs.readFile(filePath);
  const data = JSON.parse(jsonData);
  return data;
}

 

๊ฐ์ฒด๋Š” params์˜ ํ‚ค๋ฅผ ๊ฐ–๊ณ  ๊ทธ ์•ˆ์—๋Š” pid ํ‚ค๊ฐ€ ์žˆ๋Š” ๋˜ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค. ์ด id๋ฅผ ๊ฐ’์œผ๋กœ ์ทจํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒŒ ๋ชจ๋“  ID์— ์ ์šฉ๋˜๋ฉด ๊ฐ์ฒด๋กœ ๊ฐ€๋“ ์ฐฌ ๋ฐฐ์—ด์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ด๊ฒŒ ๋ฐ”๋กœ ์ด paths์— ํ•„์š”ํ•œ ๊ตฌ์กฐ๋กœ paths๋ฅผ params๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

export async function getStaticPaths() {
  const data = await getData();
  const ids = data.products.map((product) => product.id);
  const pathWithParams = ids.map((id) => ({ params: { pid: id } }));

  return {
    paths: pathWithParams,
    fallback: "blocking", // can also be true or 'blocking'
  };
}

fallback์€ ๋‹ค์‹œ false๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์š”์ฒญ ๊ฐ€๋Šฅํ•œ ID์˜ ํŽ˜์ด์ง€๋ฅผ ์ „๋ถ€ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. 

 

103. ๋Œ€์ฒด ํŽ˜์ด์ง€ & "Not Found" ํŽ˜์ด์ง€

 

fallback: false

pathsWithParams๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ ์Œ๋งŒ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฐ์—ด๋กœ [pid]์˜ ๊ฐ’์œผ๋กœ๋Š” p1, p2, p3๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค. dummy-backend.js ํŒŒ์ผ์—๋Š” ์„ธ ๊ฐ€์ง€ ID ๋ฐ–์— ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์‚ฌ์ „ ์ƒ์„ฑ๋˜์ง€ ์•Š์€ ID์˜ ํŽ˜์ด์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ๊ฒฝ์šฐ 404 ์—๋Ÿฌ ํŽ˜์ด์ง€๊ฐ€ ๋œน๋‹ˆ๋‹ค. 

 

fallback: true

fallback์„ true๋กœ ์„ค์ •ํ•จ์œผ๋กœ ํŒŒ์ผ์—์„œ ์ฐพ์„ ์ˆ˜ ์—†๋Š” ID์— ๋Œ€ํ•ด์„œ๋„ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒŒ fallback์˜ ๊ฐœ๋… ์ด๋ฉด์— ์žˆ๋Š” ๊ฑฐ์ฃ . ๋•๋ถ„์— ๋™์  ์„ธ๊ทธ๋จผํŠธ์˜ ๋ชจ๋“  ๊ฐ’์— ๋Œ€ํ•œ ํŽ˜์ด์ง€๋ฅผ ์ผ์ผ์ด ๋‹ค ์‚ฌ์ „ ์ƒ์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ fallback์„ true๋กœ ์„ค์ •ํ•˜๊ณ  /p4๋กœ ์ด๋™ํ•˜๋ฉด '์ •์˜๋˜์ง€ ์•Š์€ title ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฝ์„ ์ˆ˜ ์—†๋‹ค'๋Š” ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๊ฐ€ ๋œน๋‹ˆ๋‹ค. fallback์„ blocking์ด ์•„๋‹Œ true๋กœ ์„ค์ •ํ–ˆ์„ ๋•Œ Next.js๋Š” ์ฆ‰์‹œ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„์ง ์—†๋Š” ํŽ˜์ด์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์™€์„œ ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜๊ณ  ํ™”๋ฉด์— ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์ƒํ’ˆ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋‹ค๋ฆด ๋•Œ๋Š” ์ด ํด๋ฐฑ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋ง ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 

if (!loadedProduct) {
   return <p>Loading...</p>;
}

 

ํ•˜์ง€๋งŒ ์ด ์—ญ์‹œ ์—๋Ÿฌ๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค.

 

๋‹น์—ฐํ•œ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค. getStaticProps์—์„œ๋Š” dummy-backend.js ํŒŒ์ผ์— ์ ‘๊ทผํ•ด ํ•ด๋‹น ํŒŒ์ผ์—์„œ ID ๊ฐ’์œผ๋กœ ์ƒํ’ˆ์„ ์ฐพ๋Š”๋ฐ ์ด ํŒŒ์ผ์—๋Š” p4์— ํ•ด๋‹นํ•˜๋Š” ์ƒํ’ˆ์ด ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ํด๋ฐฑ ํŽ˜์ด์ง€์—์„œ '๋กœ๋”ฉ ์ค‘' ๋ฉ”์‹œ์ง€๊ฐ€ ์ž ๊น ๋œจ๋Š” ๋™์•ˆ NextJS๊ฐ€ ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ ์œ„ํ•ด ์š”์ฒญํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•˜๋ ค๊ณ  ํ•˜์ง€๋งŒ ์ผ์น˜ํ•˜๋Š” ์ƒํ’ˆ์ด ์—†์œผ๋‹ˆ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค. 

 

๋งŒ์•ฝ ์ƒํ’ˆ์„ ๋ถˆ๋Ÿฌ์˜ค๋ ค๊ณ  ํ•  ๋•Œ ์ƒํ’ˆ์˜ ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. 

export async function getStaticProps(context) {
  const { params } = context;
  const productId = params.pid;
  const data = await getData();
  const product = data.products.find((product) => product.id === productId);

  if (!product) {
    return { notFound: true };
  }

  return {
    props: {
      loadedProduct: product,
    },
  };
}

๋งŒ์•ฝ ์ƒํ’ˆ์„ ๋ถˆ๋Ÿฌ์˜ค๋ ค๊ณ  ํ•  ๋•Œ ์ƒํ’ˆ์˜ ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•  ์ˆ˜๋„ ์žˆ๊ฒ ์ฃ . ์š”์ฒญํ•œ ID์˜ ์ƒํ’ˆ์„ ์ฐพ์ง€ ๋ชปํ•˜๋ฉด notFound๋ฅผ true๋กœ ์„ค์ •ํ•œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์„ค์ •ํ•˜๋ฉด fallback์„ ์ฐธ์œผ๋กœ ๋‘˜ ์ˆ˜ ์žˆ๊ณ  ์‚ฌ์ „ ์ •์˜๋˜์ง€ ์•Š์€ ๋งค๊ฐœ ๋ณ€์ˆซ๊ฐ’์— ๋Œ€ํ•œ ์ƒํ’ˆ์„ ์ฐพ๊ธฐ ์œ„ํ•œ ์‹œ๋„๋ฅผ ํ•˜์ฃ . dummy-backend.js ํŒŒ์ผ์€ํ•ด๋‹น ์ƒํ’ˆ์„ ์ƒ์‚ฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ณด๋‹ค ๋™์ ์ธ ๋ฐ์ดํ„ฐ ์†Œ์Šค์ด๋‹ˆ๊นŒ์š”. ๊ทธ๋ฆฌ๊ณ  ๋งŒ์•ฝ ํŽ˜์นญ์— ์‹คํŒจํ•œ๋‹ค๋ฉด ์—๋Ÿฌ๋ฅผ ์ผ์œผํ‚ค๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋ˆ„๋ฝ๋œ ์ผ๋ฐ˜ ํŽ˜์ด์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋Œ€์‹ ์— ํŽ˜์ด์ง€๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†๋‹ค๋Š” 404 ์—๋Ÿฌ ํŽ˜์ด์ง€๋ฅผ ๋„์šฐ๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋Œ€๋กœ ์ €์žฅํ•œ ํ›„ /p4๋กœ ์ด๋™ํ•˜๋ฉด '๋กœ๋”ฉ ์ค‘' ๋ฉ”์‹œ์ง€๊ฐ€ ๋œจ๋‹ค๊ฐ€ 404 ์—๋Ÿฌ ํŽ˜์ด์ง€๊ฐ€ ๋œจ์ฃ . ๋ฐ˜๋ฉด /p3๋กœ ์ด๋™ํ•˜๋ฉด ๋‹ค์‹œ ์ •์ƒ์ ์ธ ํŽ˜์ด์ง€๊ฐ€ ๋œน๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ fallback์„ true๋กœ ์„ค์ •ํ•œ getStaticProps์—์„œ notFound ํ”„๋กœํผํ‹ฐ๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๊ฒ ์ฃ !

 

104. ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง (SSR)์„ ์œ„ํ•œ getServerSideProps์˜ ๊ฐœ์š”

getStaticProps์™€ getStaticPaths๋ฅผ ์‚ดํŽด๋ดค์Šต๋‹ˆ๋‹ค. ์ด ๋‘ ํ•จ์ˆ˜๋Š” ํ•จ๊ป˜ ์ž‘๋™ํ•˜์ง€๋งŒ ํ•ญ์ƒ ๋‘˜ ๋‹ค ํ•„์š”ํ•œ ๊ฑด ์•„๋‹ˆ์—์š”. ์ด index.js ํŒŒ์ผ์—๋Š” getStaticProps๋งŒ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‚ฌ์ „ ์ƒ์„ฑ ์‚ฌ์ „ ๋ Œ๋”๋ง์˜ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ ๋“œ๋ ธ์ฃ . ์ •์  ์ƒ์„ฑ(Static Generation)๊ณผ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง(SSR)์ž…๋‹ˆ๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ ์‚ดํŽด๋ณธ ๊ฑด ์ •์  ์ƒ์„ฑ์ž…๋‹ˆ๋‹ค. ํŽ˜์ด์ง€๋ฅผ ์ •์ ์œผ๋กœ ์‚ฌ์ „ ์ƒ์„ฑํ–ˆ์œผ๋‹ˆ๊นŒ์š”.  getStaticProps์™€ getStaticPaths ๋‚ด๋ถ€์—์„œ๋Š” ๋“ค์–ด์˜ค๋Š” ์‹ค์ œ ์š”์ฒญ์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ •์  ์ƒ์„ฑ๋งŒ์œผ๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„ ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿด ๋•Œ ์‹ค์ œ๋กœ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์œ ์ž…๋˜๋Š” ๋ชจ๋“  ์š”์ฒญ์— ๋Œ€ํ•œ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ๋ Œ๋”๋งํ•˜๋Š” ๊ฑฐ์ฃ . ๋”ฐ๋ผ์„œ ๋งค์ดˆ๋Š” ์•„๋‹ˆ์ง€๋งŒ ์œ ์ž…๋˜๋Š” ๋ชจ๋“  ์š”์ฒญ์— ๋Œ€ํ•ด์„œ๋‚˜ ์„œ๋ฒ„์— ๋„๋‹ฌํ•˜๋Š” ํŠน์ • ์š”์ฒญ ๊ฐ์ฒด์— ์ ‘๊ทผํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ฟ ํ‚ค(Cookie)๋ฅผ ์ถ”์ถœํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์ฃ . ์ถ”ํ›„ ์ธ์ฆ(Authentication)์„ ๋‹ค๋ฃจ๋Š” ๊ฐ•์˜์—์„œ ์„ค๋ช…ํ•  ๋‚ด์šฉ์ด์ง€๋งŒ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง์—์„œ ์„ค๋ช…ํ•˜๊ณ  ์‹ถ๋„ค์š”. NextJS๋Š” ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง์„ ์œ„ํ•œ ์ฝ”๋“œ๋„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰ ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ํŽ˜์ด์ง€ ์š”์ฒญ์ด ์„œ๋ฒ„์— ๋„๋‹ฌํ•  ๋•Œ๋งˆ๋‹ค ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๋นŒ๋“œ ์‹œ๊ฐ„์ด๋‚˜ ๋งค์ดˆ๋งˆ๋‹ค ์‚ฌ์ „ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  ์„œ๋ฒ„์—์„œ๋งŒ ์ž‘๋™ํ•˜๋Š” ์ฝ”๋“œ์ฃ .

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ฐฐํฌํ•œ ํ›„ ์œ ์ž…๋˜๋Š” ๋ชจ๋“  ์š”์ฒญ์— ๋Œ€ํ•ด์„œ๋งŒ ์žฌ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. getServerSideProps์— ์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š”๋ฐ์š”. getStaticProps์ฒ˜๋Ÿผ ์ด ์—ญ์‹œ๋„ ๋น„๋™๊ธฐ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ ํŒŒ์ผ์—๋งŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์ฃ . ํ•˜์ง€๋งŒ ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ ํŒŒ์ผ์— ์ด๋Ÿฐ ํ•จ์ˆ˜๊ฐ€ ์žˆ์œผ๋ฉด NextJS๊ฐ€ ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์šฐ๋ฆฌ๊ฐ€ ๋‹ค๋ฃฌ getStaticProps ํ•จ์ˆ˜๋‚˜ getServerSideProps ํ•จ์ˆ˜ ์ค‘ ํ•˜๋‚˜๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ถฉ๋Œ์„ ์ผ์œผํ‚ค๋‹ˆ๊นŒ์š”. ๋‘˜ ๋‹ค ์ปดํฌ๋„ŒํŠธ์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜๋กœ  NextJS๊ฐ€ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์‹คํ–‰๋˜๋Š” ์‹œ์ ์—๋Š” ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. 

 

105. ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง์— "getServerSideProps" ์‚ฌ์šฉํ•˜๊ธฐ

user-profile.js ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด๋ด…์‹œ๋‹ค.

export default function UserProfilePage(props) {
  return <h1>{props.username}</h1>;
}

export async function getServerSideProps(context) {
  return {
    props: {
      username: "Max",
    },
  };
}

์‚ฌ์šฉ์ž์— ๋Œ€ํ•œ ๊ตฌ์ฒด์ ์ธ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€ ํ™”๋ฉด์— ์ถœ๋ ฅํ•˜๋Š” ๊ฒŒ ๋ชฉ์ ์ด์ฃ . ์ด์ „์ฒ˜๋Ÿผ export default๋กœ ๋‚ด๋ณด๋‚ด์ค๋‹ˆ๋‹ค. ๋‹จ, ์ด ํŽ˜์ด์ง€์—๋Š” ์‚ฌ์ „ ๋ Œ๋”๋ง์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์–ด์š”. ์–ด๋–ค ์‚ฌ์šฉ์ž๊ฐ€ ๋ Œ๋”๋งํ•˜๋Š”์ง€๋ฅผ ๋จผ์ € ํŒŒ์•…ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด์ฃ . URL์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž ID๋ฅผ ์œ ์ถ”ํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ด๋Ÿฐ ์‹์œผ๋กœ ๋™์  ๋ผ์šฐํŒ… ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒ ์ฃ . ํ•˜์ง€๋งŒ ๊ทธ๋Ÿด ๊ฒฝ์šฐ, ์ด ID๋กœ ๋ธŒ๋ผ์šฐ์ €์— ์ ‘์†ํ•œ ์‚ฌ๋žŒ๋“ค์ด ํ•ด๋‹น ์‚ฌ์šฉ์ž์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์ฃ . ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ์ƒํ™ฉ์€ ์•„๋‹ˆ์ฃ . ์šฐ๋ฆฌ๋Š” ์š”์ฒญ์„ ๋ณด๋‚ธ ์‚ฌ์šฉ์ž๊ฐ€ ๋ˆ„๊ตฐ์ง€ ํ™•์ธํ•˜๋Š” ๊ฒŒ ๋ชฉ์ ์ž…๋‹ˆ๋‹ค.

 

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์€ ์ฟ ํ‚ค์™€ ํ—ค๋”๊ฐ€ ๋“  ์š”์ฒญ ๊ฐ์ฒด์— ์ ‘๊ทผํ•ด์„œ ์–ด๋Š ์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญ์„ ๋ณด๋ƒˆ๋Š”์ง€ ์•Œ์•„๋‚ด๋Š” ๊ฒ๋‹ˆ๋‹ค. getServerSideProps์˜ ์ „ํ˜•์ ์ธ ์‚ฌ์šฉ ์‚ฌ๋ก€์ฃ . ์–ด๋Š ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘๊ทผํ•˜๋Š”์ง€๋„ ๋ชจ๋ฅด๊ณ  ์ฟ ํ‚ค์—๋„ ์ ‘๊ทผํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์ด ํŽ˜์ด์ง€์— ์‚ฌ์ „ ๋ Œ๋”๋ง์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์–ด์š”. ๋”ฐ๋ผ์„œ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ๋‚ด๋ณด๋‚ด์•ผ(export) ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ”๋กœ getServerSideProps๋ผ๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜์ฃ . ๊ทธ๋ฆฌ๊ณ  ์ฝ˜ํ…์ŠคํŠธ(context)๋ผ๋Š” ๊ฐ์ฒด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ฐ์ฒด ํ•˜๋‚˜๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐ˜ํ™˜ํ•  ๊ฐ์ฒด๋Š” getStaticProps์™€ ๊ฐ™์€ ํฌ๋งท์œผ๋กœ ์„ค์ •ํ•ด์•ผ ํ•˜์ฃ . ๋”ฐ๋ผ์„œ ๊ฐ์ฒด ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ถ€๋ถ„์€ ๋˜‘๊ฐ™์•„์š”. props ํ‚ค๋Š” ํ•„์ˆ˜๊ณ , notFound ํ‚ค๋Š” ์žˆ์–ด๋„ ๋˜๊ณ  ์—†์–ด๋„ ๋˜์ฃ . redirect ํ‚ค๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๊ณ ์š” revalidate ํ‚ค๋งŒ ์ฃผ์˜ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด ํ‚ค๋Š” ํ•„์š”ํ•˜์ง€ ์•Š์„๋ฟ๋”๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์— ์„ค์ •ํ•  ์ˆ˜๋„ ์—†์ฃ . ์ •์˜ํ•œ getServerSideProps ํ•จ์ˆ˜๋งˆ๋‹ค ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์— ์ „๋ถ€ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์‹คํ–‰ํ•˜๊ฑฐ๋“ ์š”. ๋”ฐ๋ผ์„œ ์ผ์ • ์‹œ๊ฐ„์ด ์ง€๋‚˜๋„ ์œ ํšจ์„ฑ ์žฌ๊ฒ€์‚ฌ๋ฅผ ์‹คํ–‰ํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๊ฒŒ ํ•ญ์ƒ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์ด์ฃ . ๋”ฐ๋ผ์„œ props๋ฅผ ๊ฐ์ฒด๋กœ ๋‚ด๋ณด๋ƒ…๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ์ด๋ฆ„์ด getServerSideProps๋‹ˆ๊นŒ ๋‹น์—ฐํ•œ ๊ฑฐ์ฃ . ๊ทธ๋ฆฌ๊ณ  ์ด ํ”„๋กœํผํ‹ฐ๋Š” ํ•จ์ˆ˜๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์ฃผ์ฒด๋Š” ์—ฌ์ „ํžˆ Next.js์ฃ . ํ•˜์ง€๋งŒ, ์•ž์„œ ๋งํ–ˆ๋“ฏ์ด ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์ „์— ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ๋งˆ๋‹ค ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ฑฐ์ฃ . ์ด์ œ username ํ”„๋กœํผํ‹ฐ๋ฅผ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜์— props.username์„ ์ถœ๋ ฅํ•˜๋Š” ๊ฑฐ์ฃ . ์ €์žฅํ•œ ํ›„์— ์šฐ๋ฆฌ๊ฐ€ ๋ฐฉ๊ธˆ ์ถ”๊ฐ€ํ•œ /user-profile ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋ฉด Max๋ผ๋Š” ๊ธ€์ž๊ฐ€ ํ‘œ์‹œ๋  ๊ฒ๋‹ˆ๋‹ค. ์–ด์จŒ๋“  getServerSideProps ํ•จ์ˆ˜๊ฐ€ ์ž˜ ์ž‘๋™ํ•œ๋‹ค๋Š” ๋œป์ด์ฃ . 

ํ•˜์ง€๋งŒ ์ค‘์š”ํ•œ ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ๋ฐฐํฌ๋œ ์„œ๋ฒ„์™€ ๊ฐœ๋ฐœ ์„œ๋ฒ„์—์„œ๋งŒ ์‹คํ–‰๋œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‚ฌ์ „์— ์ƒ์„ฑ๋œ ์ •์  ํ•จ์ˆ˜๋Š” ์•„๋‹ˆ์ฃ . ์ด๋Š” ์šฐ๋ฆฌ๊ฐ€ ์•Œ์•„์•ผ ํ•  ์ค‘์š”ํ•œ ์ ์„ ์‹œ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

 

106. "getServerSideProps" ๊ณผ ์ฝ˜ํ…์ŠคํŠธ

getServerSideProps ํ•จ์ˆ˜๊ฐ€ ์„œ๋ฒ„์—์„œ๋งŒ ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฒŒ ๋ฌด์Šจ ๋ง์ผ๊นŒ์š”?

๊ทธ๊ฑด ๋ฐ”๋กœ ์ฝ˜ํ…์ŠคํŠธ(context) ๊ฐ์ฒด๋ฅผ ๋ณด์‹œ๋ฉด ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค getStaticProps ํ•จ์ˆ˜์˜ context์™€ ๋‹ฌ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜(params) ๊ฐ์ฒด๋‚˜ ๋œ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์— ์ ‘๊ทผํ•˜๋Š” ๊ฒŒ ๋์ด ์•„๋‹™๋‹ˆ๋‹ค. ์š”์ฒญ(req) ๊ฐ์ฒด ์ „์ฒด์—๋„ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์ฃ . ์‘๋‹ต(res) ๊ฐ์ฒด์— ์ ‘๊ทผํ•ด์„œ ํ•ด๋‹น ์š”์ฒญ์„ ์กฐ์ •ํ•˜๊ฑฐ๋‚˜ ํ—ค๋”๋„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๊ณ ์š”. ์ •ํ™•ํžˆ ๋งํ•˜์ž๋ฉด, context ๊ฐ์ฒด์— ๋“  ์—ฌ๋Ÿฌ ๊ฐ’๊ณผ ํ‚ค๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๊ณ  ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐ์ฒด์—๋„ ์—ฌ์ „ํžˆ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š” ๊ฒ๋‹ˆ๋‹ค. ๋™์  ์ปดํฌ๋„ŒํŠธ ํŽ˜์ด์ง€๊ฐ€ ์žˆ๋Š” ํ•œ ๊ทธ ์‚ฌ์‹ค์€ ๋ณ€ํ•จ์—†์ฃ .

๋ฌผ๋ก  ์ง€๊ธˆ์€ ์—†์ง€๋งŒ ๋งŒ์•ฝ ์ด๊ฒŒ ๋™์  ์ปดํฌ๋„ŒํŠธ ํŽ˜์ด์ง€์˜€๋‹ค๋ฉด params ๊ฐ์ฒด์—๋„ ์—ฌ์ „ํžˆ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์ฃ . ๋‹ค๋งŒ ์•ž์„œ ๋งํ–ˆ๋“ฏ์ด ๊ทธ๊ฒŒ ๋์ด ์•„๋‹ˆ๋ผ ์š”์ฒญ ๊ฐ์ฒด์™€ ์‘๋‹ต ๊ฐ์ฒด์—๋„ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š” ๊ฒ๋‹ˆ๋‹ค. Node.js, ํŠนํžˆ Express.js์— ๊ด€ํ•ด ์–ด๋Š ์ •๋„ ์•„๋Š” ๋ถ„์ด๋ผ๋ฉด ์ต์ˆ™ํ•œ ๊ฐœ๋…์ผ ๊ฒ๋‹ˆ๋‹ค ํ•ด๋‹น ์†Œํ”„ํŠธ์›จ์–ด์—์„œ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ์ฝ”๋“œ๋กœ ์š”์ฒญ ๊ฐ์ฒด์™€ ์‘๋‹ต ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฃจ๊ธฐ๋„ ํ•˜๋‹ˆ๊นŒ์š”. ๊ทธ๋ฆฌ๊ณ  ์ ์ ˆํ•œ ์‘๋‹ต์„ ์–ป์„ ๋•Œ๊นŒ์ง€ ํ•„์š”ํ•œ ๋งŒํผ ์š”์ฒญ ๊ฐ์ฒด๋ฅผ ์กฐ์ข…ํ•  ์ˆ˜๋„ ์žˆ๊ณ ์š”. ์š”์ฒญ์„ ๋‹ค์‹œ ๋ณด๋‚ด๋Š” ๋ถ€๋ถ„์€ ๊ฑฑ์ •ํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค. Next.js๊ฐ€ ๋Œ€์‹ ํ•ด์ค„ ๊ฑฐ์˜ˆ์š”. ํ•˜์ง€๋งŒ ์š”์ฒญ์ด ๊ฐ€๊ธฐ ์ „์— ์กฐ์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ์ฃ  ์˜ˆ๋ฅผ ๋“ค์–ด, ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ฟ ํ‚ค๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ ๊ฐ™์ด์š”. ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ์„œ๋ฒ„์— ๋„๋‹ฌํ•œ ์š”์ฒญ ๊ฐ์ฒด๋ฅผ ๋ถ„์„ํ•ด์„œ ๊ฑฐ๊ธฐ์„œ ๋“ค์–ด์˜ค๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ ๋ฐ›์„ ์š”์ฒญ ๊ฐ์ฒด์™€ ์‘๋‹ต ๊ฐ์ฒด๋Š” ๊ณต์‹ Node.js ๊ธฐ๋ณธ ์ž…๋ ฅ ๋ฉ”์‹œ์ง€์™€ ์‘๋‹ต ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์šฐ์„  ์š”์ฒญ ๊ฐ์ฒด์™€ ์‘๋‹ต ๊ฐ์ฒด์— ๊ฐ„๋‹จํ•˜๊ฒŒ ์ฝ˜์†” ๋กœ๊ทธ๋ฅผ ์‹คํ–‰ํ•ด ์ฃผ๊ณ  ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ์‚ดํŽด๋ณด๋„๋ก ํ•ฉ์‹œ๋‹ค.

 

์ €์žฅํ•˜๊ณ  ์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ ๊ณ ์นจํ•œ ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋ฉด ์ด๋ ‡๊ฒŒ ๊ธด ๋กœ๊ทธ๊ฐ€ ๋œฐ ๊ฒ๋‹ˆ๋‹ค. ๋‘ ๊ฐ์ฒด์— ๋‚ด์žฅ๋œ ๋ฉ”์„œ๋“œ์™€ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์—„์ฒญ ๋งŽ๊ธฐ ๋•Œ๋ฌธ์ด์ฃ . ๊ทธ๋ž˜์„œ ์—„์ฒญ ๋ณต์žกํ•œ ๊ฑด๋ฐ ์ง€๊ธˆ์€ ์ž์„ธํžˆ ๋‹ค๋ฃจ์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ, ๊ฐ€๋ น ํ—ค๋”๊ฐ€ ๋“ค์–ด์žˆ๋‹ค๋ฉด ํ•„์š”์‹œ ์ถ”์ถœํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ์€ ํ•„์š” ์—†์ง€๋งŒ ๋‚˜์ค‘์— ์ธ์ฆ ์ ˆ์ฐจ์— ๋Œ€ํ•œ ๊ฐ•์˜์—์„œ๋Š” ํ•„์š”ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋‘ ๊ฐ์ฒด๋Š” Node.js ๊ธฐ๋ณธ ์ž…๋ ฅ ๋ฉ”์‹œ์ง€์™€ ์‘๋‹ต์— ๋Œ€ํ•œ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค ์ด๋Ÿฐ ํŠน์ • ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๋Š” ๊ฒŒ ์ค‘์š”ํ•ด์ง€๋Š” ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์•ž์„œ ๋งํ•œ ํŠน์ˆ˜ ํ—ค๋”๋‚˜ ์ฟ ํ‚ค ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ ๋•Œ์ž…๋‹ˆ๋‹ค. 

107. ๋™์  ํŽ˜์ด์ง€ & "getServerSideProps"

getStaticProps๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” getStaticPaths๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ Next.js์—๊ฒŒ ์–ด๋–ค ํŽ˜์ด์ง€์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์ „ ์ƒ์„ฑํ• ์ง€๋ฅผ ์•Œ๋ ค์ค˜์•ผ ํ•˜์ง€๋งŒ getServerSideProps๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ทธ๋Ÿด ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€๊ด„ํ˜ธ๊ฐ€ ๋“ค์–ด๊ฐ„ [uid].js๋ผ๋Š” ํŒŒ์ผ์„ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์—ฌ๊ธฐ์„œ๋Š” ๊ฐ ์‚ฌ์šฉ์ž ID์— ํ• ๋‹น๋œ ์‚ฌ์šฉ์ž๋งˆ๋‹ค ๋™์  ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ getServerSideProps๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด getStaticPaths๊ฐ€ ์žˆ์„ ํ•„์š”๋„, ์žˆ์„ ์ˆ˜๋„ ์—†์Šต๋‹ˆ๋‹ค.

export default function UserIdPage(props) {
  return <h1>{props.id}</h1>;
}

export async function getServerSideProps(context) {
  const { params } = context;

  const userId = params.uid;

  return {
    props: {
      id: "userId-" + userId,
    },
  };
}

UserIdPage๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๊ณ  ์ธ์ˆ˜๋กœ๋Š” props๋ฅผ ๋‘” ๋‹ค์Œ h1 ํƒœ๊ทธ๊ฐ€ ์ ์šฉ๋œ props.id๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•˜๊ณ  ์ด๋ฅผ export default๋กœ ๋‚ด๋ณด๋‚ด ์ค๋‹ˆ๋‹ค. ์—ฌ๊ธฐ๊นŒ์ง€ ๋งˆ์นœ ๋‹ค์Œ์—๋Š” getServerSideProps ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ์ถœ๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ณผ์ •์—์„œ getStaticPaths๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๊ฐ์ฒด(Object)๋งŒ ๋ฐ˜ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ €๋Š” ์—ฌ๊ธฐ์„œ ๋‚˜์˜ค๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜(Parameter)๋ฅผ ์ด์šฉํ•ด ์ฝ˜ํ…์ŠคํŠธ(Context)์— ์ ‘๊ทผํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฐฉ๊ธˆ ๋งํ•œ params๋ฅผ ์ถ”์ถœํ•˜๊ณ  ๊ทธ params์—์„œ userId๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ๋Œ€๊ด„ํ˜ธ์— ๋„ฃ์€ ์‹๋ณ„์ž(Identifier)์ธ uid์— ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜์— ์ „๋‹ฌํ•œ ํ”„๋กœํผํ‹ฐ(Property)์—์„œ ์œ„์—์„œ ์ ‘๊ทผํ•œ id ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ณ  ์ด๊ฒƒ์„ userid- ๋ผ๋Š” ํ…์ŠคํŠธ์™€ URL์—์„œ ์ถ”์ถœํ•ด์˜จ userId๋ฅผ ๋ถ™์ธ ๊ฐ’์œผ๋กœ ์ง€์ •ํ•ด์„œ ๋”๋ฏธ ์ฝ”๋“œ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋„๋ก ํ•˜๋ฉด ์ด ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์ด ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ฝ”๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋ ค๋ฉด ๋จผ์ € [pid].js ํŒŒ์ผ์„ ์—†์• ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋‘ ๊ฐœ์˜ ๋™์  ์„ธ๊ทธ๋จผํŠธ ํŽ˜์ด์ง€๊ฐ€ pages ํด๋”์—์„œ ๋™์ผํ•œ ์ˆ˜์ค€์— ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— Next.js์—์„œ๋Š” ์Šฌ๋ž˜์‹œ(/) ๋‹ค์Œ์— ์˜ค๋Š” ๊ฐ’์ด ์—†์„ ๋•Œ ์ด๋ฅผ pid์™€ uid ์ค‘ ์–ด๋””์—์„œ ์ฒ˜๋ฆฌํ• ์ง€ ๊ตฌ๋ถ„ํ•˜์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์ด์ฃ .

{products.map((product) => (
    <li key={product.id}>
      <Link href={`/products/${product.id}`}>{product.title}</Link>
    </li>
))}

๊ทธ๋Ÿฌ๋‹ˆ [pid].js ํŒŒ์ผ์„ products ํด๋”๋กœ ์˜ฎ๊ฒจ์ฃผ๊ณ  index.js์— ์žˆ๋Š” ๋งํฌ๋ฅผ /products/${product.id}๋กœ ๋ฐ”๊ฟ”์ฃผ๋ฉด ์ด์ œ ๋” ์ด์ƒ ๋‘ ํŒŒ์ผ ๊ฐ„ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ  ์Šฌ๋ž˜์‹œ(/) ๋’ค์— ID๊ฐ€ ์˜ค๋ฉด ํ•ญ์ƒ ์‚ฌ์šฉ์ž ID ๋ผ์šฐํŠธ๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ๊นŒ์ง€ ๋งˆ์น˜๊ณ  ๊ฐœ๋ฐœ์ž ์„œ๋ฒ„๋ฅผ ๊ตฌ๋™ํ•˜๊ณ  ์ฒซ ๋ฒˆ์งธ ์‚ฌ์šฉ์ž๋ฅผ ๋œปํ•˜๋Š” /u1์„ ์ฃผ์†Œ์— ๋ถ™์ด๋ฉด userid-u1์ด ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ๋ณด๋‹ˆ ์ž˜ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. getStaticPaths ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ๋„ ์ฝ”๋“œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•œ ์ด์œ ๋Š” ์ด ์ฝ”๋“œ๋Š” ์„œ๋ฒ„์—์„œ๋งŒ ์ž‘๋™ํ•˜๋ฏ€๋กœ Next.js์—์„œ๋Š” ์•„๋ฌด ํŽ˜์ด์ง€๋„ ์‚ฌ์ „ ์ƒ์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๊ณ , ๋”ฐ๋ผ์„œ ์‚ฌ์ „ ์ƒ์„ฑํ•  ๋Œ€์ƒ์ด ์—†์œผ๋‹ˆ getStaticPaths ์ •๋ณด๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. getStaticProps๋ฅผ ์‚ฌ์šฉํ•ด ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ์ƒ์„ฑํ•  ๋•Œ๋Š” Next.js์—๊ฒŒ ์–ด๋–ค ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ’์˜ ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ์ƒ์„ฑํ•ด์•ผ ํ• ์ง€ ์•Œ๋ ค์ฃผ๊ธฐ ์œ„ํ•ด์„œ getServerSideProps๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ ์ด ๊ฒฝ์šฐ์—๋Š” ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ์ฝ”๋“œ์—์„œ ๋ชจ๋“  ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์ „ ์ƒ์„ฑํ•  ํ•„์š”๋„ ์—†๊ณ  ๋”ฐ๋ผ์„œ ๋™์  ๊ฒฝ๋กœ ๋˜ํ•œ ๋ฏธ๋ฆฌ ์„ค์ •ํ•  ํ•„์š”๋„ ์—†๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

108. "getServerSideProps" ๋‚ด๋ถ€์—์„œ ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š” ์ผ

Route (pages)                              Size     First Load JS
โ”Œ โ— / (ISR: 10 Seconds)                    2.84 kB        81.8 kB
โ”œ   /_app                                  0 B            78.9 kB
โ”œ λ /[uid]                                 375 B          79.3 kB
โ”œ โ—‹ /404                                   212 B          79.1 kB
โ”œ โ— /products/[pid] (664 ms)               470 B          79.4 kB
โ”œ   โ”œ /products/p1
โ”œ   โ”œ /products/p2
โ”œ   โ”” /products/p3
โ”” λ /user-profile                          386 B          79.3 kB
+ First Load JS shared by all              79.1 kB
  โ”œ chunks/framework-0f397528c01bc177.js   45.7 kB
  โ”œ chunks/main-5cebf592faf0463a.js        31.8 kB
  โ”œ chunks/pages/_app-aba2de2b7ae6fcb3.js  390 B
  โ”œ chunks/webpack-2369ea09e775031e.js     1.02 kB
  โ”” css/49861c0d8668ac82.css               185 B

λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)
โ—‹  (Static)  automatically rendered as static HTML (uses no initial props)
โ—  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)
   (ISR)     incremental static regeneration (uses revalidate in getStaticProps)

โœจ  Done in 6.95s.
โžœ  nextjs-pre-rendering git:(main) โœ— yarn run dev
yarn run v1.22.17
$ next dev
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
event - compiled client and server successfully in 412 ms (154 modules)
wait  - compiling / (client and server)...
event - compiled client and server successfully in 175 ms (209 modules)
(Re-) Generating...
wait  - compiling /user-profile (client and server)...
event - compiled client and server successfully in 149 ms (212 modules)
Server side code

 

consol.log ๋ฌธ์žฅ์„ ์ถ”๊ฐ€ํ•ด์„œ ์ด ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋  ๋•Œ Server side code๋ผ๋Š” ํ…์ŠคํŠธ๊ฐ€ ๋กœ๊น…๋˜๋„๋ก ํ•ฉ์‹œ๋‹ค. ํŒŒ์ผ์„ ์ €์žฅํ•œ ๋’ค run npm build ๋ช…๋ น์–ด๋กœ ์ด ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์–ธ์ œ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜์—ˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ„ฐ๋ฏธ๋„ ์˜์—ญ์„ ์ข€ ๋” ํ‚ค์›Œ์„œ ์ž˜ ๋ณด์ด๊ฒŒ ํ•˜๊ณ ์š”. ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ์ƒ์„ฑ(Pre-generate)ํ–ˆ๋‹ค๋Š” ๋กœ๊ทธ๊ฐ€ ๋ณด์ด๋Š”๋ฐ ์—ฌ๊ธฐ์„œ ์ฃผ๋ชฉํ•  ์ ์€ ์ด์ „๊ณผ ๋˜‘๊ฐ™์€ ์ˆ˜์˜ ํŽ˜์ด์ง€๊ฐ€ ์ƒ์„ฑ๋๋‹ค๋Š” ๊ฒ๋‹ˆ๋‹ค. ์Šฌ๋ž˜์‹œ(/) ๋’ค์— ์•„๋ฌด๊ฒƒ๋„ ์—†์„ ๋•Œ๋Š” ์žฌ๊ฒ€์ฆ(Revalidation)์„ ๊ฑฐ์นœ ์ดˆ๊ธฐ ํŽ˜์ด์ง€๊ฐ€ ์žˆ๊ณ  ๊ทธ๋ฆฌ๊ณ  404 ์˜ค๋ฅ˜ ์ฝ”๋“œ ํŽ˜์ด์ง€์™€ P1, P2, P3 ์ œํ’ˆ์— ๋Œ€ํ•œ ์ œํ’ˆ ํŽ˜์ด์ง€๋„ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ํŽ˜์ด์ง€๊ฐ€ ์—†๋Š” ์ด์œ ๋Š” ๋žŒ๋‹ค(Lambda) ๊ธฐํ˜ธ๋กœ ์—”๋“œ ์‹œ๊ทธ๋„(End signal)์„ ํ‘œ์‹œํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ [uid].js ํŒŒ์ผ๋„ ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜์ฃ . ๋žŒ๋‹ค ๊ธฐํ˜ธ๊ฐ€ ์žˆ๋Š” ํŽ˜์ด์ง€๋“ค์€ ์‚ฌ์ „ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  ์„œ๋ฒ„ ์ธก์—์„œ๋งŒ ์‚ฌ์ „ ๋ Œ๋”๋ง๋๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค.

 

user-profile์—์„œ getServerSideProps๋ฅผ ๊ทธ๋ฆฌ๊ณ  [uid].js์—์„œ๋Š” getServerSideProps๋ฅผ ์‚ฌ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ํŽ˜์ด์ง€๊ฐ€ ์‚ฌ์ „ ์ƒ์„ฑ๋˜์ง€ ์•Š์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ๊นŒ์ง€ ๋งˆ์น˜๊ณ  ๋‹ค์‹œ npm start ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•œ ๋’ค localhost:3000๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋ฉด ์ด๋Ÿฐ ํŽ˜์ด์ง€๊ฐ€ ๋‚˜์˜ค๊ณ  ๋’ค์— /user-profile์„ ๋ถ™์ด๋ฉด Max๋ผ๋Š” ํ…์ŠคํŠธ๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ npm start๋กœ ํ”„๋กœ๋•์…˜ ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•œ ํ„ฐ๋ฏธ๋„์„ ํ™•์ธํ•ด ๋ณด๋ฉด Server side code๋ผ๋Š” ํ…์ŠคํŠธ๊ฐ€ ๋กœ๊น…๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์ฃ . ์œ„์˜ consol.log ๊ฐ์ฒด(Object)์˜ ์ถœ๋ ฅ๊ฐ’์ด ๋‚˜์™”์œผ๋‹ˆ ์ด ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์ง€๋งŒ ์•ž์„œ ๋ณด์—ฌ๋“œ๋ฆฐ ๊ฒƒ์ฒ˜๋Ÿผ ์ด ํŽ˜์ด์ง€๋Š” ์‚ฌ์ „ ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

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

109.  ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ๋ฐ์ดํ„ฐ fetching ์˜ ๊ฐœ์š” (์–ธ์ œ ์‚ฌ์šฉํ•ด์•ผ ํ• ๊นŒ?)

 

Next.js ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•˜๋‹ค ๋ณด๋ฉด ๋•Œ๋กœ๋Š” ์‚ฌ์ „ ๋ Œ๋”๋ง์„ ํ•  ํ•„์š”๊ฐ€ ์—†๊ฑฐ๋‚˜ ์‚ฌ์ „ ๋ Œ๋”๋ง์„ ํ•  ์ˆ˜ ์—†๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๊ฒŒ ๋  ๊ฒ๋‹ˆ๋‹ค.

๊ฐฑ์‹  ์ฃผ๊ธฐ๊ฐ€ ์žฆ์€ ๋ฐ์ดํ„ฐ์ธ ๊ฒฝ์šฐ์ธ๋ฐ์š”. ์˜ˆ๋ฅผ ๋“ค์–ด ์ฃผ์‹ ๋ฐ์ดํ„ฐ๋ฅผ ์–ด๋–ค ํŽ˜์ด์ง€์— ํ‘œ์‹œํ•˜๋ ค๊ณ  ํ•˜๋Š”๋ฐ ๊ทธ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งค์ดˆ๋งˆ๋‹ค ์—ฌ๋Ÿฌ ์ฐจ๋ก€ ๋ณ€๊ฒฝ๋œ๋‹ค๋ฉด ํ”„๋ฆฌํŽ˜์นญ๊ณผ ์‚ฌ์ „ ๋ Œ๋”๋ง์„ ํ•˜๋Š” ์˜๋ฏธ๊ฐ€ ์—†์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŽ˜์ด์ง€๋ฅผ ๋ฐฉ๋ฌธํ•˜๋ฉด ์ด๋ฏธ ๊ทธ ๋ฐ์ดํ„ฐ๋Š” ๊ณผ๊ฑฐ์˜ ๊ฒƒ์ด ๋˜์–ด ์žˆ์„ ํ…Œ๋‹ˆ๊นŒ์š”. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ํŽ˜์ด์ง€๋ฅผ ๋ฐฉ๋ฌธํ–ˆ์„ ๋•Œ ๋กœ๋”ฉ ์•„์ด์ฝ˜์„ ํ‘œ์‹œํ•˜๊ณ  ๋ฐฉ๋ฌธํ–ˆ์„ ๋•Œ์˜ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์ด ์‚ฌ์šฉ์ž ์ž…์žฅ์—์„œ๋Š” ๊ฐ€์žฅ ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ์˜ˆ๋กœ๋Š” ํŠน์ • ์œ ์ €์—๋งŒ ํ•œ์ •๋˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜จ๋ผ์ธ ์‡ผํ•‘๋ชฐ์˜ ์ตœ๊ทผ ์ฃผ๋ฌธ ๋‚ด์—ญ๊ณผ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์ด์— ํ•ด๋‹นํ•˜์ฃ . ๊ณ„์ •์— ์ ‘์†ํ•ด์„œ ํ”„๋กœํ•„ ํŽ˜์ด์ง€์—์„œ ํŠน์ •ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์—ด๋žŒํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ๋ Œ๋”๋งํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. 

๋˜๋Š” ๋ฐ์ดํ„ฐ์˜ ์ผ๋ถ€๋ถ„๋งŒ ํ‘œ์‹œํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ํ‘œ์‹œ๋˜๋Š” ๋Œ€์‹œ๋ณด๋“œ ํŽ˜์ด์ง€์˜ ๊ฒฝ์šฐ์—๋Š” ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ์— ๋ถˆ๋Ÿฌ์˜ค๋„๋ก ํ•˜๋ฉด ์„œ๋ฒ„์—์„œ ๋Œ€์‹œ๋ณด๋“œ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์ด ๋งŽ์ด ์†Œ์š”๋˜๋ฏ€๋กœ ๊ฐœ๋ฐœ ๋‹จ๊ณ„์—์„œ ์ด ํŽ˜์ด์ง€๋ฅผ ์‚ฌ์ „ ๋ Œ๋”๋งํ•  ์ด์œ ๊ฐ€ ์—†๊ฒ ์ฃ . ๊ทธ ํŽ˜์ด์ง€์˜ ์ •๋ณด๋Š” ๋‹ค๋ถ„ํžˆ ๊ฐœ์ธ์ ์ด๊ฑฐ๋‚˜ ๋ณ€๋™์ด ์žฆ์„ ํ…Œ๋‹ˆ๊นŒ์š”. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ์‚ฌ์ „ ๋ Œ๋”๋ง๋ณด๋‹ค๋Š” ์ฃผ์–ด์ง„ React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ํฌํ•จ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€์— ๋ฐฉ๋ฌธํ•  ๋•Œ๋งŒ ๋ถˆ๋Ÿฌ์˜ค๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ช‡ ๊ฐ€์ง€ ๋Œ€ํ‘œ์ ์ธ ์˜ˆ๋ฅผ ์‚ดํŽด๋ดค๊ณ  ๊ทธ ์™ธ์—๋„ ๋งŽ์€ ์ƒํ™ฉ์—์„œ ๋ฐ์ดํ„ฐ ํ”„๋ฆฌํŽ˜์นญ๊ณผ ํŽ˜์ด์ง€ ์‚ฌ์ „ ์ƒ์„ฑ ๋ฐฉ์‹์ด ์ œ๋Œ€๋กœ ๊ธฐ๋Šฅํ•˜์ง€ ๋ชปํ•˜๊ฑฐ๋‚˜ ํ•„์š”ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋”ฐ๋ผ์„œ ๊ทธ ๊ฒฝ์šฐ์—๋Š” ์‚ฌ์ „ ์ƒ์„ฑ์ด๋‚˜ ํ”„๋ฆฌํŽ˜์นญ ๋Œ€์‹  React ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ธฐ์กด ์ ‘๊ทผ๋ฒ•์ธ useEffect๋‚˜ fetch ๊ฐ™์€ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด์„œ ํด๋ผ์ด์–ธํŠธ ์ธก React ์•ฑ ๋‚ด์˜ API์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ฆ‰, getStaticProps๋‚˜ getServerSideProps ๋Œ€์‹  ์„œ๋ฒ„๊ฐ€ ์•„๋‹ˆ๋ผ ํด๋ผ์ด์–ธํŠธ์—์„œ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋  ๋•Œ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋„๋ก ๊ตฌ์ถ•ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

110. ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ๋ฐ์ดํ„ฐ fetching ๊ตฌํ˜„ํ•˜๊ธฐ

firebase์— ์ ‘์† > Realtime Database๋ฅผ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. 

 

 

111. useSWR ์ฐธ๊ณ ์‚ฌํ•ญ

useSWR๋กœ ์ž‘์—…์„ ํ•  ๋•Œ๋Š”, ๊ธฐ๋ณธ “fetcher”๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  1. useSWR(<request-url>, (url) => fetch(url).then(res => res.json()

 

112. useSWR NextJS ํ›… ์‚ฌ์šฉํ•˜๊ธฐ

https://swr.vercel.app/ko 

 


https://www.udemy.com/course/nextjs-react-incl-two-paths/

 

๋ฐ˜์‘ํ˜•