๐Ÿš€ Next.js 9์žฅ: Parallel & Intercepting Routes โ€” ๋ชจ๋‹ฌ๊ณผ ๋ผ์šฐํŒ…์˜ ๊ทนํ•œ

๐Ÿ“‹ ๊ฐœ์š”

Parallel Routes์™€ Intercepting Routes๋กœ URL ๊ธฐ๋ฐ˜ ๋ชจ๋‹ฌ์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์›๋‹ˆ๋‹ค.

๐Ÿ“‹ ๋ชฉ์ฐจ


๐Ÿ“Œ ์ด ๋ฌธ์„œ๋ฅผ ์ฝ๊ธฐ ์ „์—

โฑ๏ธ ์˜ˆ์ƒ ์ฝ๊ธฐ ์‹œ๊ฐ„: 20๋ถ„(์ „์ฒด) / ํ•ต์‹ฌ ํŒŒํŠธ๋งŒ: 10๋ถ„

๐Ÿ—บ๏ธ ์ด ๋ฌธ์„œ์˜ ํ๋ฆ„
๋…๋ฆฝ๋œ ์˜์—ญ ๋ณ‘๋ ฌ ๋ Œ๋”๊ธฐ(@) โ†’ ํ๋ฆ„ ๊ฐ€๋กœ์ฑ„๊ธฐ((..)) โ†’ ์ด ๋‘˜์„ ์กฐํ•ฉํ•œ ๊ถ๊ทน์˜ "๊ณต์œ  URL ๋ชจ๋‹ฌ" ํŒจํ„ด ๋งˆ์Šคํ„ฐ

๐ŸŽฏ ์ด ๋ฌธ์„œ๋ฅผ ๋‹ค ์ฝ์œผ๋ฉด ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ

  • ์ธ์Šคํƒ€๊ทธ๋žจ, ํ•€ํ„ฐ๋ ˆ์ŠคํŠธ์ฒ˜๋Ÿผ (1) ํ”ผ๋“œ ์œ„์—์„œ๋Š” ๋ชจ๋‹ฌ๋กœ ๋œจ๊ณ , (2) ๋‚จ์—๊ฒŒ ์นดํ†ก์œผ๋กœ ๊ณต์œ ํ•œ URL์„ ๋ˆ„๋ฅด๋ฉด ์ „์ฒดํ™”๋ฉด ์ „์šฉ ํŽ˜์ด์ง€๋กœ ์ ‘์†๋˜๋Š” ์ด์ค‘ ๋ผ์šฐํŒ… ์•„ํ‚คํ…์ฒ˜๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ•˜๋‚˜์˜ layout.tsx ์•ˆ์—์„œ A, B, C ๊ตฌ์—ญ์ด ๊ฐ๊ฐ ๋‚จ์˜ ๋ˆˆ์น˜ ์•ˆ ๋ณด๊ณ  ๋…๋ฆฝ์ ์ธ ๋กœ๋”ฉ/์—๋Ÿฌ ํ™”๋ฉด์„ ๋ฟœ์–ด๋‚ด๋Š” "๋Œ€์‹œ๋ณด๋“œ ๋ณ‘๋ ฌ ๋ Œ๋”๋ง" ์„ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ—บ๏ธ ์ด ๋ฌธ์„œ์˜ ๋ฐฐ๊ฒฝ ์„ธ๊ณ„๊ด€: '์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ'

  • ์˜์ฒ (์ƒˆ๋กœ ์˜จ ์ฃผ๋‹ˆ์–ด): "๋ฆฌ๋“œ ๋‹˜... ํ”ผ๋“œ์—์„œ ์‚ฌ์ง„์„ ํด๋ฆญํ•˜๋ฉด ๋ชจ๋‹ฌ๋กœ ๋„์›Œ์คฌ๊ฑฐ๋“ ์š”. ๊ทธ๋Ÿฐ๋ฐ ์‚ฌ์šฉ์ž๊ฐ€ ํŒ์—…์„ ๋‹ซ์œผ๋ ค๊ณ  '๋’ค๋กœ ๊ฐ€๊ธฐ'๋ฅผ ๋ˆŒ๋ €๋”๋‹ˆ ์‚ฌ์ดํŠธ ๋ฐ–์œผ๋กœ ํŠ•๊ฒจ ๋‚˜๊ฐ”๋Œ€์š”! URL์ด ์•ˆ ๋ณ€ํ•ด์„œ ๊ทธ๋Ÿฐ ๊ฒƒ ๊ฐ™์€๋ฐ, ๊ทธ๋ ‡๋‹ค๊ณ  ์ƒˆ ํŽ˜์ด์ง€๋กœ ์ด๋™์‹œํ‚ค์ž๋‹ˆ ๋ฐฐ๊ฒฝ ํ”ผ๋“œ๊ฐ€ ๋‹ค ์‚ฌ๋ผ์ ธ์š”. ๐Ÿ˜ญ"
  • ์˜ํ˜ธ(FE ๋ฆฌ๋“œ): "์˜์ฒ  ๋‹˜... ๋ชจ๋‹ฌ์˜ ์ตœ๊ณ  ๋‚œ์ œ์ธ 'URL ๋™๊ธฐํ™” ๋ ˆ์ด์–ด' ๋ฅผ ๋งˆ์ฃผํ•˜์…จ๊ตฐ์š”! Next.js์˜ @folder (๋ณ‘๋ ฌ ๋ผ์šฐํŠธ) ์™€ (..) (๊ฐ€๋กœ์ฑ„๊ธฐ ๋ผ์šฐํŠธ) ๋ฅผ ์„ž์–ด ์“ฐ๋ฉด, URL์€ ์ •ํ™•ํžˆ ๋ฐ”๋€Œ๋ฉด์„œ๋„ ๋ฐฐ๊ฒฝ ํ™”๋ฉด์€ ๊ทธ๋Œ€๋กœ ์œ ์ง€๋˜๋Š” ์ธ์Šคํƒ€๊ทธ๋žจ ๋บจ์น˜๋Š” ํŒ์—…์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๊ณ ์š”!"

๐Ÿค” ์™œ ์•Œ์•„์•ผ ํ•˜๋Š”๊ฐ€

๊ณผ๊ฑฐ ๋ฆฌ์•กํŠธ ์‹œ์ ˆ์— ํŒ์—…/๋ชจ๋‹ฌ ๋„์šฐ๊ธฐ๋Š” ์‰ฌ์› ์–ด. const [isOpen, setIsOpen] = useState(false) ํ•˜๋‚˜ ์„ ์–ธํ•˜๊ณ  ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง({isOpen && <Modal/>}) ๋•Œ๋ฆฌ๋ฉด ๋์ด์—ˆ์ง€.
ํ•˜์ง€๋งŒ ์ด ๋ฐฉ์‹์—” ์น˜๋ช…์ ์ธ ๊ฒฐํ•จ์ด ์žˆ์—ˆ๋‹จ๋‹ค.

  1. ๋’ค๋กœ ๊ฐ€๊ธฐ ๋ถˆ๊ฐ€๋Šฅ: ๋ธŒ๋ผ์šฐ์ € ํžˆ์Šคํ† ๋ฆฌ(URL)์— ๊ธฐ๋ก์ด ์•ˆ ๋‚จ์•„์„œ, ๋’ค๋กœ ๊ฐ€๊ธฐ๋ฅผ ๋ˆ„๋ฅด๋ฉด ๋ชจ๋‹ฌ๋งŒ ๊บผ์ง€๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ์•ž ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ด๋ฒ„๋ฆผ.
  2. ๊ณต์œ  ๋ถˆ๊ฐ€๋Šฅ: ์ด "์‚ฌ์ง„ ๋ชจ๋‹ฌ์ด ๋–  ์žˆ๋Š” ์ƒํƒœ" ์ž์ฒด๋ฅผ ์นœ๊ตฌํ•œํ…Œ ๋งํฌ๋กœ ๋ณต์‚ฌํ•ด์„œ ์ค„ ์ˆ˜๊ฐ€ ์—†์Œ.
  3. SEO ๋ถ•๊ดด: ํฌ๋กค๋Ÿฌ ์ž…์žฅ์—์„œ๋Š” ์ˆจ๊ฒจ์ง„ div ๋ฉ์–ด๋ฆฌ์ผ ๋ฟ, ๋…๋ฆฝ๋œ ๋ฌธ์„œ(์‚ฌ์ง„ ์ƒ์„ธ ์ •๋ณด)๋กœ ์ธ์‹ํ•˜์ง€ ๋ชปํ•จ.

์ด๊ฑธ ๊ณ ์น˜๋ ค๋ฉด ๋ชจ๋‹ฌ์„ ๋„์šธ ๋•Œ ๊ฐ•์ œ๋กœ URL์„ ๋ฐ”๊ฟ”์•ผ ํ•˜๋Š”๋ฐ(์˜ˆ: /feed -> /photo/123), ๊ณผ๊ฑฐ์—” URL์ด ๋ฐ”๋€Œ๋ฉด ๋ฐฐ๊ฒฝ์— ๊น”๋ ค์žˆ๋˜ ํ”ผ๋“œ ๋ชฉ๋ก์ด ์‹น ๋‚ ์•„๊ฐ€๊ณ  ์ƒˆ๋กœ์šด ๋ฐฑ์ง€ ๋ Œ๋” ์˜์—ญ(๋ชจ๋‹ฌ๋งŒ ๋ฉ๊ทธ๋Ÿฌ๋‹ˆ ์žˆ๋Š” ํŽ˜์ด์ง€) ์ด ๋‚˜ํƒ€๋‚˜๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ์—ˆ์–ด.

์ด ๋ชจ๋‹ฌ ๋”œ๋ ˆ๋งˆ๋ฅผ "์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ํ”„๋ ˆ์ž„์›Œํฌ" ์ฐจ์›์—์„œ ๊ฐ€์žฅ ์šฐ์•„ํ•˜๊ฒŒ, ์™„๋ฒฝํ•˜๊ฒŒ ๋ฐ•์‚ด ๋‚ด๋ฒ„๋ฆฐ Next.js์˜ ์ž๋ž‘์Šค๋Ÿฌ์šด ๋‘ ๊ฐ€์ง€ ๊ณ ๊ธ‰ ํŒŒ์ผ ์‹œ์Šคํ…œ ๋ฃฐ์„ ๋ฐฐ์›Œ๋ณด์ž.


๐Ÿ—๏ธ ๋น„์œ ๋กœ ๋จผ์ € ์ดํ•ดํ•˜๊ธฐ

๐Ÿง’ 5์‚ด์—๊ฒŒ ์„ค๋ช…ํ•œ๋‹ค๋ฉด? (์˜์ˆ˜๋„ค ๊ตญ๋ฐฅ์ง‘์˜ ๋…๋ฆฝ ํ…Œ์ด๋ธ”๊ณผ ์‹œ์‹ ๊ฐ€๋กœ์ฑ„๊ธฐ)

Parallel Routes (@) : 1์ธ์šฉ ์นธ๋ง‰์ด ํ…Œ์ด๋ธ”
์‹๋‹น ํ•œ๊ฐ€์šด๋ฐ์— ๋…๋ฆฝ๋œ ๋ฐฅ์ƒ 3๊ฐœ(@table1, @table2, @table3) ๊ฐ€ ๋†“์—ฌ ์žˆ๋Š” ๊ฑฐ์•ผ.
1๋ฒˆ ์†๋‹˜์ด ๊น๋‘๊ธฐ๋ฅผ ๋” ๋‹ฌ๋ผ๊ณ  ํ•ด๋„(@analytics) , 2๋ฒˆ ์†๋‹˜์€ ์ž๊ธฐ ๊ตญ๋ฐฅ์„ ์กฐ์šฉํžˆ ๋จน๊ณ  ์žˆ์–ด.
์˜† ํ…Œ์ด๋ธ”์—์„œ ๊ทธ๋ฆ‡์„ ๊นจ๋œจ๋ ค๋„(@error) , ๋‚ด ํ…Œ์ด๋ธ” ์†๋‹˜์€ ์•„๋ฌด ์ผ ์—†๋‹ค๋Š” ๋“ฏ ๋ฐฅ์„ ๋จน์„ ์ˆ˜ ์žˆ๋Š” ์™„๋ฒฝํ•œ ๋…๋ฆฝ ์‹์‚ฌ ๊ณต๊ฐ„ ์ด์•ผ.

Intercepting Routes ((..)): ์ฃผ๋ฐฉ ์•ž ๊ฐ€๋กœ์ฑ„๊ธฐ ์‹œ์‹ํšŒ
์›๋ž˜ "ํŠน๋Œ€ ์ˆ˜์œก" ์ฃผ๋ฌธ(photo/1) ์€ "์•ˆ์ชฝ ๋‹จ์ฒด ๋ฐฉ" ์œผ๋กœ ๋ฐฐ๋‹ฌ๋˜์–ด์•ผ ํ•ด.
๊ทธ๋Ÿฐ๋ฐ ์†๋‹˜์ด ๋ณต๋„๋ฅผ ์ง€๋‚˜๊ฐ€๋‹ค๊ฐ€ ์ฃผ๋ฐฉ ์ž…๊ตฌ์—์„œ "์ž ๊น! ๊ทธ ์ˆ˜์œก ๋‚˜ ํ•œ ์ ๋งŒ ๋ง›๋ณด๊ฒŒ ํ•ด์ค˜!" ํ•˜๊ณ  ๋ชฉ์ ์ง€๋กœ ๊ฐ€๋˜ ์ˆ˜์œก์„ ์ค‘๊ฐ„์— ๋‚š์•„์ฑ„์„œ(Intercept) ํ˜„์žฌ ์žˆ๋Š” ๋ณต๋„(ํ”ผ๋“œ ํ™”๋ฉด) ์—์„œ ํ•œ ์ž… ๋จน์–ด๋ณด๋Š” ๋งˆ์ˆ  ์ด์•ผ.
๋‹ค ๋จน๊ณ  ์ ‘์‹œ๋ฅผ ๋Œ๋ ค์ฃผ๋ฉด(๋’ค๋กœ ๊ฐ€๊ธฐ) , ๋‹ค์‹œ ์›๋ž˜ ์ž๋ฆฌ๋กœ ๋Œ์•„๊ฐ€๊ณ , ์•„์˜ˆ ์ฒ˜์Œ๋ถ€ํ„ฐ "๋‹จ์ฒด ๋ฐฉ" ์œผ๋กœ ๋“ค์–ด์˜จ ์†๋‹˜(์ง์ ‘ URL ์ ‘์†) ์€ ์ œ๋Œ€๋กœ ๋œ ์ˆ˜์œก ํ•œ ์ƒ์„ ๋ฐ›๊ฒŒ ๋ผ.

๐Ÿงฉ Parallel Routes (@folder): ํ•œ ์ง€๋ถ• ๋‘ ๊ฐ€์กฑ ๐ŸŸข

๋จผ์ € ๋ณ‘๋ ฌ ๋ผ์šฐํŠธ์•ผ. ํด๋” ์ด๋ฆ„ ์•ž์— ๊ณจ๋ฑ…์ด(@)๋ฅผ ๋ถ™์ด๋ฉด, Next.js๋Š” ์ด๊ฑธ ๋‹จ์ˆœํ•œ URL ๊ฒฝ๋กœ ์กฐ๊ฐ์œผ๋กœ ํ•ด์„ํ•˜์ง€ ์•Š๊ณ  "๋ถ€๋ชจ Layout์— ๊ฝ‚์•„ ๋„ฃ์„ ๋…๋ฆฝ๋œ ์Šฌ๋กฏ(Slot)" ์œผ๋กœ ์ทจ๊ธ‰ํ•ด.

์ƒํ™ฉ: ๋ณต์žกํ•œ ๊ด€๋ฆฌ์ž ๋Œ€์‹œ๋ณด๋“œ

๋Œ€์‹œ๋ณด๋“œ(Root) ์•ˆ์— 1) ์‚ฌ์šฉ์ž ํ†ต๊ณ„ํ‘œ์™€ 2) ์ตœ์‹  ์•Œ๋ฆผ์ฐฝ ๋‘ ๊ฐœ์˜ ๊ฑฐ๋Œ€ํ•œ ๊ตฌ์—ญ์ด ์žˆ์–ด.

app/
 โ”œโ”€ layout.tsx      (๋ผˆ๋Œ€ ๋ ˆ์ด์•„์›ƒ)
 โ”œโ”€ page.tsx        (๊ฐ€์šด๋ฐ ๊ธฐ๋ณธ ๊ตฌ์—ญ)
 โ”œโ”€ @analytics/     (๊ณจ๋ฑ…์ด! ์Šฌ๋กฏ A)
 โ”‚   โ””โ”€ page.tsx
 โ””โ”€ @notifications/ (๊ณจ๋ฑ…์ด! ์Šฌ๋กฏ B)
     โ””โ”€ page.tsx

์•„๋น  ๋ ˆ์ด์•„์›ƒ(layout.tsx)์˜ ๋งˆ๋ฒ• ์Šฌ๋กฏ ์กฐ๋ฆฝ

@ํŒŒ์ผ๋ช… ํด๋”๋ฅผ ๋งŒ๋“ค๋ฉด, Next.js ํ”„๋ ˆ์ž„์›Œํฌ ์ฝ”์–ด๊ฐ€ ์ž๋™์œผ๋กœ layout.tsx ์ปดํฌ๋„ŒํŠธ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ(Props)์— ๊ทธ ์ด๋ฆ„๊ณผ ๋˜‘๊ฐ™์€ children์„ ๋ชฐ๋ž˜ ์ฃผ์ž…ํ•ด์ค˜! ์—„์ฒญ๋‚œ ํ‘๋งˆ๋ฒ•์ด์ง€.

// app/layout.tsx
export default function DashboardLayout({
  children, // ์›๋ž˜ ๋“ค์–ด์˜ค๋˜ ๊ธฐ๋ณธ page.tsx ๊ตฌ์—ญ
  analytics, // @analytics ํด๋” ๋‚ด๋ถ€์˜ ๋ Œ๋”๋ง ๊ฒฐ๊ณผ๋ฌผ์ด ํ†ต์งธ๋กœ ๋“ค์–ด์˜ด! (๋งˆ์ˆ )
  notifications, // @notifications ๋‚ด๋ถ€ ๊ฒฐ๊ณผ๋ฌผ 
}: {
  children: React.ReactNode
  analytics: React.ReactNode
  notifications: React.ReactNode
}) {
  return (
    <body>
      <main className="grid">
        <div className="center"> {children} </div>
        
        {/* ํ•œ ์ง€๋ถ•(layout) ์•„๋ž˜์— 3๊ฐ€์กฑ์ด ๋…๋ฆฝ๋œ ์Šคํฌ๋ฆฐ์œผ๋กœ ๊ณต์กดํ•œ๋‹ค! */}
        <aside className="left"> {analytics} </aside>
        <aside className="right"> {notifications} </aside>
      </main>
    </body>
  )
}

์ด ์ง“์„ ์™œ ํ•˜๋‚˜์š”? (์ตœ๋Œ€ ์žฅ์ )
์ € 3๊ฐœ์˜ ๊ตฌ์—ญ(children, analytics, notifications)์€ ์™„์ „ํžˆ ๋‚จ๋‚จ์ฒ˜๋Ÿผ ํ–‰๋™ํ•ด.

  • ๋งŒ์•ฝ ํ†ต๊ณ„(analytics) ๋ฐ์ดํ„ฐ ์กฐํšŒ๊ฐ€ 5์ดˆ๋‚˜ ๊ฑธ๋ ค์„œ ๋กœ๋”ฉ ์ค‘(์ž์ฒด loading.tsx ๋ณด์œ )์ด๊ฑฐ๋‚˜ ํ„ฐ์ ธ๋„(์ž์ฒด error.tsx ๋ณด์œ ), ์˜ค๋ฅธ์ชฝ์˜ ์•Œ๋ฆผ์ฐฝ(notifications)์€ ๋ˆˆ์น˜ ์•ˆ ๋ณด๊ณ  0.1์ดˆ ๋งŒ์— ๋ Œ๋”๋ง์„ ๋๋‚ด๊ณ  ํ˜ผ์ž ๊ทธ๋ ค์ ธ. ์™„๋ฒฝํ•œ ๊ฒฉ๋ฆฌ ๋ณด๋ฃจ๊ฐ€ ๋˜๋Š” ๊ฑฐ์•ผ!

๐ŸŒฑ Intercepting Routes ((..)): ๋‚ด๊ฐ€ ์ฑ„๊ฐ€๋Š” ๋งˆ์ˆ  ๐ŸŸก

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

(.) : ๋‚˜์™€ ๊ฐ™์€ ํด๋” ๋ ˆ๋ฒจ ๊ฒฝ๋กœ ๊ฐ€๋กœ์ฑ„๊ธฐ
(..) : ๋‚˜๋ณด๋‹ค ํ•œ ๋‹จ๊ณ„ ์œ—๋ฐฉ(๋ถ€๋ชจ) ๊ฒฝ๋กœ ๊ฐ€๋กœ์ฑ„๊ธฐ
(..)(..) : ๋‘ ๋‹จ๊ณ„ ์œ—๋ฐฉ ๊ฐ€๋กœ์ฑ„๊ธฐ
(...) : ์•„์˜ˆ ์ตœ์ƒ๋‹จ app/ ๊ธฐ์ค€ ๋ฃจํŠธ(Root) ๊ฐ€๋กœ์ฑ„๊ธฐ

๐ŸŽฏ ์˜์ฒ ์ด์˜ ์ธ์Šคํƒ€๊ทธ๋žจ ๋งŒ๋“ค๊ธฐ ๋ฏธ์…˜

์šฐ๋ฆฌ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ /photo/123 ์ด๋ผ๋Š” ๊ณ ์œ  ์ฃผ์†Œ๋ฅผ ๊ฐ€์ง„ ์ •์งํ•˜๊ณ  ์ปค๋‹ค๋ž€ "์‚ฌ์ง„ ์ „์šฉ ์ƒˆ ํŽ˜์ด์ง€"๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด. (๋‚จํ•œํ…Œ ์นดํ†ก์œผ๋กœ ๊ณต์œ ํ–ˆ์„ ๋•Œ ๋–จ์–ด์ง€๋Š” ๋„์ฐฉ์ง€)

app/
 โ”œโ”€ feed/
 โ”‚   โ””โ”€ page.tsx      (๊ฒŒ์‹œ๋ฌผ ๋ชฉ๋ก)
 โ””โ”€ photo/
     โ””โ”€ [id]/
         โ””โ”€ page.tsx  (๊ทธ๋ƒฅ ์ ‘์†ํ•˜๋ฉด ๋œจ๋Š” ์ปค๋‹ค๋ž€ ์ „์ฒด์‚ฌ์ง„ ํŽ˜์ด์ง€)

์ด ์ƒํƒœ์—์„œ feed/page.tsx ์•ˆ์˜ ์‚ฌ์ง„ ๋งํฌ <Link href="/photo/123"> ๋ฅผ ํด๋ฆญํ•˜๋ฉด? ์•ˆํƒ€๊น๊ฒŒ๋„ ํ™”๋ฉด ๋ฐฐ๊ฒฝ์ด ํ•˜์–—๊ฒŒ ์‹น ๋‹ค ์ง€์›Œ์ง€๋ฉฐ ๋ป˜๊ฑด ์ „์ฒดํ™”๋ฉด ์‚ฌ์ง„ ํŽ˜์ด์ง€ /photo/123 ์œผ๋กœ ๋„˜์–ด๊ฐ€๋ฒ„๋ ค.

์ด๊ฑธ ๋ง‰์œผ๋ ค๋ฉด? ํ”ผ๋“œ(Feed) ๊ตฌ์—ญ ๋‚ด๋ถ€์—์„œ, ์›๋ž˜ /photo/ ๋ฐฉ์œผ๋กœ ํ˜๋Ÿฌ ๋“ค์–ด๊ฐ€์•ผ ํ•  ๋ผ์šฐํŒ… ํ๋ฆ„์„ ๊ฐ€๋กœ์ฑ„๋ฉด ๋ผ!


๐Ÿ›ก๏ธ ์ธ์Šคํƒ€๊ทธ๋žจ ๋ชจ๋‹ฌ ์„ค๊ณ„: ๋‘ ๊ธฐ์ˆ ์˜ ์™„๋ฒฝํ•œ ์•™์ƒ๋ธ” ๐Ÿ”ด

์ด์ œ ์œ„์—์„œ ๋ฐฐ์šด ๋‘ ๊ฐœ์˜ ๋ฌด๊ธฐ(๋ณ‘๋ ฌ @, ๊ฐ€๋กœ์ฑ„๊ธฐ (..))๋ฅผ ํ•ฉ์ฒดํ•ด ์ „์„ค์˜ ๋ฌด๊ธฐ(Soft Navigation Modal)๋ฅผ ๋ฒผ๋ ค๋‚ด์ž.

์™„๋ฒฝํ•œ ๋ชจ๋‹ฌ ํด๋” ๊ตฌ์กฐ ์„ค๊ณ„๋„

app/
 โ”œโ”€ layout.tsx
 โ”œโ”€ feed/
 โ”‚   โ”œโ”€ layout.tsx    โ˜… ๋ชจ๋‹ฌ ์Šฌ๋กฏ์„ ๊ตฌ๋น„ํ•ด๋†“์Œ
 โ”‚   โ”œโ”€ page.tsx      โ˜… <Link href="/photo/1">๊ฐ€ ์žˆ๋Š” ๋ชฉ๋ก
 โ”‚   โ””โ”€ @modal/       โ˜… [Parallel] ๋ชจ๋‹ฌ์„ ๋„์šธ ์ „์šฉ ๋…๋ฆฝ ๋ณ‘๋ ฌ ์Šฌ๋กฏ
 โ”‚       โ”œโ”€ default.tsx     (ํ‰์†Œ ๋กœ๋”ฉ ์ „์šฉ ํˆฌ๋ช…์ธ๊ฐ„ ๋ทฐ)
 โ”‚       โ””โ”€ (..)photo/      โ˜… [Intercept] ํ๋ฆ„ ๊ฐ€๋กœ์ฑ„๊ธฐ ํด๋”! (ํ”ผ๋“œ์˜ ํ˜•์ œ์ธ photo๋ฅผ ๋‚š์•„์ฑ”)
 โ”‚           โ””โ”€ [id]/
 โ”‚               โ””โ”€ page.tsx โ˜… ์—ฌ๊ธฐ๊ฐ€ ๋ฐ”๋กœ ํ”ผ๋“œ ๋ฐฐ๊ฒฝ์„ ๊น”๊ณ  ๋œจ๋Š” "๋ชจ๋‹ฌ ๋ฐ•์Šค" ์ปดํฌ๋„ŒํŠธ!
 โ”‚
 โ””โ”€ photo/            โ˜… [Original] ์—ฌ๊ธฐ๋Š” ๋ณ€ํ•จ ์—†์ด ์กด์žฌํ•˜๋Š” "๊ทผ๋ณธ ์ „์ฒดํ™”๋ฉด" ๋ชฉ์ ์ง€.
     โ””โ”€ [id]/
         โ””โ”€ page.tsx  โ˜… ์นดํ†ก/์ธ์Šคํƒ€๋กœ ๋ณต์‚ฌ๋œ ๋งํฌ ์ง๊ฒฐ ์ ‘์† ์‹œ ๋œจ๋Š” ๊ฑฐ๋Œ€ํ•œ ํ™”๋ฉด!

[๋งˆ๋ฒ•์ด ํŽผ์ณ์ง€๋Š” ์ˆœ๊ฐ„]

  1. ์ƒํ™ฉ 1: ์นดํ†ก์œผ๋กœ ๋งํฌ ๊ณต์œ ๋ฐ›์•„ ๋ธŒ๋ผ์šฐ์ €์— ์Œฉ์œผ๋กœ ๋ณต๋ถ™ ์ ‘์†ํ–ˆ์„ ๋•Œ (Hard Navigation)
    ๋ˆ„๊ฐ€ /photo/1 ์ณค๋‹ค. Next.js ์—”์ง„์€ "๊ฐ€๋กœ์ฑŒ ์ถœ๋ฐœ์ง€๊ฐ€ ์—†๋„ค?" ํ•˜๊ณ  ์ •์งํ•˜๊ฒŒ ๊ทผ๋ณธ ๊ฒฝ๋กœ์ธ ๋งจ ๋ฐ‘๋ฐ”๋‹ฅ app/photo/[id]/page.tsx ์ฐํŽ˜์ด์ง€๋ฅผ ์—ด์–ด์„œ ๋ณด์—ฌ์ค€๋‹ค.

  2. ์ƒํ™ฉ 2: ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์ดํŠธ ๋‚ด์—์„œ ํ”ผ๋“œ(feed) ์ธ๋„ค์ผ์„ ๋งˆ์šฐ์Šค๋กœ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ํด๋ฆญํ•  ๋•Œ (Soft Navigation)
    ํ”ผ๋“œ(feed/page.tsx) ์•ˆ์—์„œ <Link href="/photo/1"> ํด๋ฆญ!
    ๊ฒฝ๋กœ๊ฐ€ ์ด๋™ํ•˜๋ ค๋Š”๋ฐ, ์•—! feed ํด๋” ๋‚ด๋ถ€์— ์ž ๋ณต ๊ฒฝ์ฐฐ (..)photo ๊ฐ€ "์žก์•˜๋‹ค ์š”๋†ˆ!" ํ•˜๊ณ  ๋‚š์•„์ฑˆ๋‹ค.
    ๋‚š์•„์ฑˆ ์ด ๊ฐ€์งœ ๋ชจ๋‹ฌ ๊ป๋ฐ๊ธฐ๋Š” ์•„๊นŒ ๊ณจ๋ฑ…์ด๋กœ ๋šซ์–ด๋‘” @modal ๋ณ‘๋ ฌ ์Šฌ๋กฏ ์œ„์น˜์—(์•„๋น  ๋ ˆ์ด์•„์›ƒ ์˜†์ž๋ฆฌ์— ๋ผ์–ด์„œ) ๋ฟ… ํ•˜๊ณ  ํŠ€์–ด๋‚˜์˜จ๋‹ค!

๊ฒฐ๊ณผ? URL ์ฐฝ์—” /photo/1 ์ด๋ผ๊ณ  ์˜ˆ์˜๊ฒŒ ์ฐํ˜€์žˆ์ง€๋งŒ, ํ™”๋ฉด์€ ์›๋ž˜ ์žˆ๋˜ feed ๋ชฉ๋ก ์œ„์— ๋ชจ๋‹ฌ(@modal)์ด ๋–  ์žˆ๋Š” ๊ถ๊ทน์˜ ์•„ํ‚คํ…์ฒ˜๊ฐ€ ์™„์„ฑ๋œ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ํฐ ๋’ค๋กœ ๊ฐ€๊ธฐ๋ฅผ ๋ˆ„๋ฅด๋ฉด ๋ชจ๋‹ฌ๋งŒ ๊บผ์ง€๊ณ  ๋‹ค์‹œ ๊ทผ์›์ง€(ํ”ผ๋“œ URL)๋กœ ์™ ํšŒ๊ท€ํ•œ๋‹ค.

๐ŸŒŸ layout.tsx ํ•ฉ์ฒด ์ฝ”๋“œ

// app/feed/layout.tsx
export default function FeedLayout({
  children,
  modal // @modal ํด๋” ์ž์ฒด๊ฐ€ Props๋กœ ๊ฝ‚ํž˜!
}: { children: React.ReactNode, modal: React.ReactNode }) {
  return (
    <>
      {children} {/* ํ”ผ๋“œ ๋ชฉ๋ก (๋ฐฐ๊ฒฝ์— ์˜์›ํžˆ ๊น”๋ ค์žˆ์Œ) */}
      {modal}    {/* ๊ฐ€๋กœ์ฑ„๊ธฐ ๋ ˆ์ด๋”. ํ‰์†Œ์—” ๋น„์–ด์žˆ๋‹ค๊ฐ€ ๋ˆ„๋ฅด๋ฉด ์ด ์ž๋ฆฌ์— ํŒ์—…์ด ๋™‡! */}
    </>
  )
}

๐Ÿ’ฅ ์—๋Ÿฌ ํ•ด๊ฒฐ ์นดํƒˆ๋กœ๊ทธ

์—๋Ÿฌ ๋ฉ”์‹œ์ง€๊ฐ€ ๋œจ๋ฉด Ctrl+F๋กœ ๊ฒ€์ƒ‰ํ•ด๋ด.

โŒ ๋ชจ๋‹ฌ ํด๋” ์„ธํŒ…์„ ๋‹ค ํ–ˆ๋Š”๋ฐ๋„ ๋นŒ๋“œ๋‚˜ ํŽ˜์ด์ง€ ์ด๋™ ์‹œ ํ„ฐ์ง‘๋‹ˆ๋‹ค (404 Error)

์›์ธ: Parallel Route (@ํด๋”)๋ฅผ ์‹ฌ์–ด๋†“๊ณ , ํ‰์ƒ์‹œ ๋ Œ๋”๋ง์— ํ•„์š”ํ•œ default.tsx ๋ฅผ ๋ฏธ๋ฐฐ์น˜ํ•จ.
ํ•ด๊ฒฐ์ฑ…: Next.js ๋ณ‘๋ ฌ ๋ผ์šฐํŠธ๋Š” "ํ™”๋ฉด์— ๋„์›Œ์ค„ URL ๋Œ€์ƒ์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์„ ๋•Œ" ํ‘œ์‹œํ•  ๋นˆ ๊นกํ†ต ์Šคํฌ๋ฆฐ ํŒŒ์ผ์„ ๊ฐ•์š”ํ•œ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋ช… default.tsx ๋ฅผ ๋งŒ๋“ค๊ณ  ์ฟจํ•˜๊ฒŒ return null; ํ•˜๋‚˜๋งŒ ์ ์–ด์„œ ๋ฐ˜ํ™˜์‹œํ‚ค๋ฉด ๋งˆ๋ฒ•์ฒ˜๋Ÿผ ์ถฉ๋Œ์ด ์‚ฌ๋ผ์ง„๋‹ค.

โŒ (..) ๊ฒฝ๋กœ๋ฅผ ํ•œ ๋ฒˆ ์ผ๋Š”๋ฐ ๊ฐ€๋กœ์ฑ„๊ธฐ๊ฐ€ ์ž‘๋™์„ ์•ˆ ํ•˜๊ณ  ๋ณธ ํŽ˜์ด์ง€๋กœ ์ž๊พธ ํŠ•๊น๋‹ˆ๋‹ค.

์›์ธ: (..) ์งฌ์งฌ ํด๋”์˜ ๊นŠ์ด ๋งค์นญ ์˜ค๋ฅ˜.
์˜ˆ๋ฅผ ๋“ค์–ด ๊ฐ€๋กœ์ฑ„๋ ค๋Š” ๋Œ€์ƒ์ด app/movies/[id] ์ธ๋ฐ, ์ž ๋ณต ๊ฒฝ์ฐฐ ์œ„์น˜๊ฐ€ app/feed/@modal/(..)movies ๋ผ ์น˜์ž.
๊ฒฝ์ฐฐ์€ "๋‚ด ๋ถ€๋ชจ(feed)๋ž‘ ๊ฐ™์€ ๊ธ‰์˜ ๋ฐฉ(movies)" ๋งŒ ๋‚š์•„์ฑŒ ์ˆ˜ ์žˆ๋‹ค! ๋งŒ์•ฝ ๊นŠ์ด๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์–ด๊ธ‹๋‚œ๋‹ค๋ฉด ๊ฐ€๋กœ์ฑ„๊ธฐ๋Š” ๋ฐœ๋™ ์กฐ๊ฑด์„ ์ถฉ์กฑํ•˜์ง€ ๋ชปํ•ด ์ •์งํ•œ ๋งํฌ๋กœ ํŠ•๊ฒจ๋ฒ„๋ฆฐ๋‹ค. (๊นŠ์ด๊ฐ€ ํ—ท๊ฐˆ๋ฆฌ๋ฉด ํด๋” ํŠธ๋ฆฌ๋ฅผ ์ข…์ด์— ๊ทธ๋ ค๋ณด๋Š” ๊ฑธ ์›์น™์œผ๋กœ ํ•˜๋ผ!)


๐Ÿ ์ด๋ฒˆ์— ๋ฐฐ์šด ๋‚ด์šฉ ์ด์ •๋ฆฌ

๊ธฐ๋Šฅ ๊ตฌ๋ถ„์ฃผ์š” ์—ญํ•  ์„ค๋ช…์‹ค๋ฌด ์‚ฌ์šฉ ๋นˆ๋„ & ์˜ˆ์‹œ
@folder (Parallel)ํ•œ ํƒญ ๋ฌธ์„œ ํ™”๋ฉด์„ ์—ฌ๋Ÿฌ ๊ฐœ์˜ "๋…๋ฆฝ ์ƒ์กด ๊ตฌ์—ญ"์œผ๋กœ ์นผ๋กœ ์ชผ๊ฐฌ๋Œ€์‹œ๋ณด๋“œ 3๋ถ„ํ•  ๋ทฐ, ๋กœ๊ทธ์ธ ๋‹ค์ด์–ผ๋กœ๊ทธ ๊ตฌ์—ญ ํ™•๋ณด (๋งค์šฐ ๋†’์Œ)
(..) (Intercept)์ด๋™ํ•˜๋ ค๋Š” ๋ชฉ์ ์ง€์˜ URL๊ณผ ๋‚ด์šฉ๋ฌผ์„ ๋‚š์•„์ฑ„ "ํ˜„์žฌ ์žˆ๋Š” ๋ทฐํฌํŠธ์— ๋ฎ์–ด์”€"์ธ์Šคํƒ€ ์‚ฌ์ง„ ํ”ผ๋“œ ํ™•๋Œ€, ํ•€ํ„ฐ๋ ˆ์ŠคํŠธ ์นด๋“œ ํด๋ฆญ ์‹œ (๋†’์Œ)
์œ„ ๋‘ ๊ฐœ ์กฐํ•ฉ ๋งˆ์ˆ URL ์ผ์น˜, ๋ธŒ๋ผ์šฐ์ € ๋’ค๋กœ ๊ฐ€๊ธฐ ๋™์ž‘, ์ง์ ‘ ์ ‘์†(๊ณต์œ ) ์ฒ˜๋ฆฌ๊นŒ์ง€ ์™„๋ฒฝ ์ปค๋ฒ„ํ•˜๋Š” ๋ผ์šฐํŒ… ๋ ˆ๋ฒจ์˜ ๋ชจ๋‹ฌ ํ˜๋ช…ํ”„๋กœ๋•ํŠธ ์ตœ๊ณ ๋‚œ๋„ UX ํŒ์—… (Next.js๋ฅผ ๋„์ž…ํ•˜๋Š” ์ด์œ  ๊ทธ ์ž์ฒด!)

๐Ÿ’ก ํ•œ ์ค„๋กœ ๊ธฐ์–ตํ•˜๊ธฐ
ํŒ์—… ๋ชจ๋‹ฌ์„ ๋งŒ๋“ค ๋•Œ useState(false) Boolean ์Šค์œ„์น˜์—๋งŒ ์˜์กดํ•˜๋˜ ํ—ˆ์ ‘ํ•œ ์‹œ์ ˆ์€ ๋๋‚ฌ๋‹ค! ๊ฒฝ๋กœ(URL)๋ฅผ ๊ฐ€๋กœ์ฑ„๊ณ ((..)), ๊ทธ ๊ฐ€๋กœ์ฑˆ ํ™”๋ฌผ์„ ๋‚ด ์˜†์— ๋ณ‘๋ ฌ ๋ถ€ํ•˜(@)๋กœ ์‘ค์…” ๋ฐ•์œผ๋ฉด ์ง„์งœ ์•ฑ ๊ฐ™์€ ๋„ค์ดํ‹ฐ๋ธŒ ํŒŒ์›Œ ๋ผ์šฐํŒ… ๋ชจ๋‹ฌ์ด ํƒ„์ƒํ•œ๋‹ค!


๐Ÿ“ ๋งˆ๋ฌด๋ฆฌ ํ€ด์ฆˆ

๋ฐฐ์› ์œผ๋ฉด ํ•œ ๋ฒˆ ๋น„ํ‹€์–ด์„œ ํ™•์ธํ•ด๋ด์•ผ ํ•ด.

Q1. ์˜์ฒ ์ด๊ฐ€ ๋ณ‘๋ ฌ ํด๋”๋ฅผ ์ด์šฉํ•ด app/layout.tsx์— @chat ํด๋”(์šฐ์ธก ๊ณ ์ • ์ฑ„ํŒ…์ฐฝ ์Šฌ๋กฏ)๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค. ๋ฉ”์ธ ํ”ผ๋“œ์ธ /feed/page.tsx ๋‚ด๋ถ€์—์„œ ๋งํฌ๋ฅผ ํด๋ฆญํ•ด /user/setting ํŽ˜์ด์ง€๋กœ ์ด๋™ํ–ˆ๋‹ค. ์ด๋•Œ ์šฐ์ธก์˜ ๊ณ ์ • ์ฑ„ํŒ…์ฐฝ ์Šฌ๋กฏ(@chat)์€ ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? (์ฑ„ํŒ…์ฐฝ ๋‚ด๋ถ€ URL ๋งคํ•‘์ด ์—†์„ ๊ฒฝ์šฐ)

โœ… ์ •๋‹ต: ์†Œํ”„ํŠธ ๋‚ด๋น„๊ฒŒ์ด์…˜(Link ํด๋ฆญ) ์‹œ ๋ณ‘๋ ฌ ๋ผ์šฐํŠธ๋Š” ๊ธฐ์กด ํ™”๋ฉด(์ƒํƒœ)์„ ๊ธฐ์–ตํ•ด ์œ ์ง€๋œ๋‹ค.

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค: ์†Œํ”„ํŠธ ๋‚ด๋น„๊ฒŒ์ด์…˜(Link ํด๋ฆญ)์œผ๋กœ ํŽ˜์ด์ง€ ์ด๋™ ๋ฐœ์ƒ ์‹œ, ๋ณ‘๋ ฌ ๋ผ์šฐํŠธ๋Š” URL ์ฐฝ์ด ๋ฐ”๋€Œ๋”๋ผ๋„ ๊ธฐ์กด ํ™”๋ฉด(์ƒํƒœ)์„ ๊ธฐ์–ตํ•ด ์œ ์ง€(์œ ์‹ค ๋ฐฉ์–ด) ํ•œ๋‹ค. (์ฆ‰, ์ฑ„ํŒ… ๋Œ€ํ™” ํžˆ์Šคํ† ๋ฆฌ์™€ ์ž…๋ ฅ์ฐฝ์€ ์ „ํ˜€ ๋Š๊ธฐ์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ ๋‚จ์•„์žˆ๋‹ค.) ๋‹จ, ์œ ์ €๊ฐ€ ๊ทธ ์ƒํƒœ์—์„œ ํ‚ค๋ณด๋“œ "F5(์ƒˆ๋กœ๊ณ ์นจ)"(Hard Navi)๋ฅผ ๋•Œ๋ ค๋ฒ„๋ฆฌ๋ฉด Next.js๋Š” "/user/setting URL ํ™˜๊ฒฝ์— ๋งค์นญ๋˜๋Š” @chat ํŒŒ์ธ ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ"์ด๋ž€ ํŒ์ •์„ ๋‚ด๋ฆฌ๊ณ  ํ„ฐ์ ธ๋ฒ„๋ฆฌ๋ฏ€๋กœ, ์ด ์ถฉ๋Œ์„ ๋ฐฉ์–ดํ•  default.tsx๋ฅผ ๋นˆ ๊นกํ†ต์œผ๋กœ ํ•˜๋‚˜ ์ƒ์„ฑํ•ด๋‘ฌ์•ผ ์™„๋ฒฝํ•ด์ง„๋‹ค.

Q2. ์˜ํ˜ธ ๋ฆฌ๋“œ๊ฐ€ ์งˆ๋ฌธํ–ˆ๋‹ค. "์ธ์Šคํƒ€๊ทธ๋žจ ๊ณต์œ  ํด๋ฆญ์„ ๋Œ€๋น„ํ•ด ๊ฐ€๋กœ์ฑ„๊ธฐ(Intercepting) ๋ผ์šฐํŠธ๋ฅผ ํด๋” ํŠธ๋ฆฌ์— ๋‹ค ์„ธํŒ…ํ–ˆ์–ด์š”. ๊ทธ๋Ÿฐ๋ฐ ์šฐ๋ฆฌ ๋ชจ๋ฐ”์ผ ์•ฑ์ด๋‚˜ ์›น์‚ฌ์ดํŠธ ํŒ์—…์—์„œ X (๋‹ซ๊ธฐ) ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ๋Š”, ๋ชจ๋‹ฌ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ํ•จ์ˆ˜์ ์œผ๋กœ ์–ด๋–ค ๋ช…๋ น์–ด๋ฅผ ๋‚ ๋ ค์•ผ ๋ฐฐ๊ฒฝ ํ”ผ๋“œ๋ฅผ ๋ถ€์ˆ˜์ง€ ์•Š๊ณ  ๋ชจ๋‹ฌ ๊ป๋ฐ๊ธฐ๋งŒ ์šฐ์•„ํ•˜๊ฒŒ ์ฒ ์ˆ˜(๋‹ซ๊ธฐ)์‹œํ‚ฌ ์ˆ˜ ์žˆ์„๊นŒ์š”?"

โœ… ์ •๋‹ต: Next.js๊ฐ€ ์ œ๊ณตํ•˜๋Š” router.back()์„ ์‚ฌ์šฉํ•œ๋‹ค.

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค: ํŒ์—…(๊ฐ€๋กœ์ฑˆ ์Šฌ๋กฏ) ์ปดํฌ๋„ŒํŠธ๋Š” ์‚ฌ์‹ค์ƒ ๊ธฐ์กด ํ”ผ๋“œ ์œ„์— URL ๋ ˆ์ด์–ด๊ฐ€ ํ•œ ๊บผํ’€ ๋ฎ์ธ(Push) ์ƒํƒœ์ด๋ฏ€๋กœ, '๋‹ซ๊ธฐ' ๋ฒ„ํŠผ์˜ onClick ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์— useRouter() ํ›…์—์„œ ๊บผ๋‚ธ ๋„ฅ์ŠคํŠธ ์ „์šฉ const router = useRouter(); router.back() ์„ ๋‹ฌ์•„์ฃผ๋Š” ์ˆœ๊ฐ„, ํžˆ์Šคํ† ๋ฆฌ๊ฐ€ ํ•œ ๊ฐœ ๋น ์ง€๋ฉด์„œ ๊ณจ๋ฑ…์ด ์Šฌ๋กฏ(@modal)์— ๋งคํ•‘๋œ ๋ชจ๋‹ฌ UI ๋ทฐํฌํŠธ๋งŒ ์ฆ๋ฐœํ•˜๊ณ  ํ•˜์ธต๋ถ€ ํ”ผ๋“œ๋Š” ์˜จ์ „ํžˆ ์œ ์ง€๋˜๋Š” ์ตœ์ƒ๊ธ‰ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋™์ž‘์„ ์—ฐ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿฃ ์˜์ฒ ์ด์˜ ํ‡ด๊ทผ ์ผ๊ธฐ

์˜ค๋Š˜์€ ์ •๋ง ๋งˆ๋ฒ• ๊ฐ™์€ ๋ชจ๋‹ฌ์˜ ์„ธ๊ณ„๋ฅผ ๊ฒฝํ—˜ํ–ˆ์–ด! ์˜ˆ์ „์—” ๋ชจ๋‹ฌ ํ•˜๋‚˜ ๋„์šฐ๋ ค๋ฉด URL์€ ํฌ๊ธฐํ•˜๊ณ  ๊ทธ๋ƒฅ ์ƒํƒœ๊ฐ’์œผ๋กœ๋งŒ ์–ต์ง€๋กœ ๋น„๋ณ๋Š”๋ฐ, ์ด์ œ๋Š” ์ธ์Šคํƒ€๊ทธ๋žจ์ฒ˜๋Ÿผ URL๋„ ๋ฐ”๋€Œ๋ฉด์„œ ๋ฐฐ๊ฒฝ์€ ์œ ์ง€๋˜๋Š” ๊ณ ๊ธ‰ ๊ธฐ์ˆ ์„ ์“ธ ์ˆ˜ ์žˆ๊ฒŒ ๋์–ด.

๐Ÿ’ก ์˜ค๋Š˜์˜ ๊ตํ›ˆ: "URL์„ ๋ฐ”๊พธ๋ฉด์„œ๋„ ๋ฐฐ๊ฒฝ์„ ์ง€ํ‚ค๊ณ  ์‹ถ๋‹ค๋ฉด? ํ˜„์žฌ ๋ผ์šฐํŠธ์—์„œ ๋ชฉ์ ์ง€๋ฅผ ๋‚š์•„์ฑ„๊ณ (@ํด๋” + (..)ํด๋”), ๊ทธ ์ž๋ฆฌ์— ๋ชจ๋‹ฌ์„ ์–น์ž."

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


๐Ÿ”— ๋” ์•Œ์•„๋ณด๊ธฐ