Search
๐Ÿš

Routing

๐Ÿง‘๐Ÿผโ€๐Ÿš€ ๋ผ์šฐํŒ…์„ ์•Œ์•„์•ผ ํ•˜๋Š” ์ด์œ 

โ—์ƒˆ๋กœ๊ณ ์นจ ์—†์ด ์‚ฌ์šฉ์ž์—๊ฒŒ ๋” ๋‚˜์€ ํ•˜์ดํผ๋งํฌ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด

๐Ÿ™‹๐Ÿปโ€โ™‚๏ธ ์ด ๋ฌธ์„œ๋ฅผ ๋ณด๊ณ  ๋‚˜๋ฉด

๋ผ์šฐํŒ…์„ ์œ„ํ•œ ์ „ํ†ต์ ์ธ ๋งํฌ, AJAX, PJAX ๋ฐฉ์‹์„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.
Browser History API๋ฅผ ์ด์šฉํ•˜์—ฌ ์ƒˆ๋กœ ๊ณ ์นจ ์—†์ด ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ผ์šฐํŒ…

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

1. ์ „ํ†ต์ ์ธ ๋งํฌ ๋ฐฉ์‹

์ „ํ†ต์  ๋งํฌ ๋ฐฉ์‹์€ link tag๋กœ ๋™์ž‘ํ•˜๋Š” ๊ธฐ๋ณธ์ ์ธ ์›นํŽ˜์ด์ง€์˜ ๋™์ž‘ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.
link tag(<a href="about.html">About</a> ๋“ฑ)์„ ํด๋ฆญํ•˜๋ฉด href์˜ ๊ฐ’์ธ ๋ฆฌ์†Œ์Šค์˜ ๊ฒฝ๋กœ๊ฐ€ URL์˜ path์— ์ถ”๊ฐ€๋˜์–ด ์ฃผ์†Œ์ฐฝ์— ๋‚˜ํƒ€๋‚˜๊ณ  ํ•ด๋‹น ๋ฆฌ์†Œ์Šค๋ฅผ ์„œ๋ฒ„์— ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ ์„œ๋ฒ„๋Š” html๋กœ ํ™”๋ฉด์„ ํ‘œ์‹œํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ์™„์ „ํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ํด๋ผ์ด์–ธํŠธ์— ์‘๋‹ตํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์„œ๋ฒ„ ๋ Œ๋”๋ง์ด๋ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋Š” ์„œ๋ฒ„๊ฐ€ ์‘๋‹ตํ•œ html์„ ์ˆ˜์‹ ํ•˜๊ณ  ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ ์ด์ „ ํŽ˜์ด์ง€์—์„œ ์ˆ˜์‹ ๋œ html๋กœ ์ „ํ™˜ํ•˜๋Š” ๊ณผ์ •์—์„œ ์ „์ฒด ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜๊ฒŒ ๋˜๋ฏ€๋กœ ์ƒˆ๋กœ ๊ณ ์นจ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
์ด ๋ฐฉ์‹์€ JavaScript๊ฐ€ ํ•„์š” ์—†์ด ์‘๋‹ต๋œ html๋งŒ์œผ๋กœ ๋ Œ๋”๋ง์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ ํŽ˜์ด์ง€๋งˆ๋‹ค ๊ณ ์œ ์˜ URL์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ history ๊ด€๋ฆฌ ๋ฐ SEO ๋Œ€์‘์— ์•„๋ฌด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ค‘๋ณต๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ•  ๋•Œ ๋งˆ๋‹ค ์ˆ˜์‹ ํ•ด์•ผ ํ•˜๋ฉฐ, ์ „์ฒด ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜๋Š” ๊ณผ์ •์—์„œ ์ƒˆ๋กœ ๊ณ ์นจ์ด ๋ฐœ์ƒํ•˜์—ฌ ์‚ฌ์šฉ์„ฑ์ด ์ข‹์ง€ ์•Š์€ ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

2. AJAX๋ฅผ ํ†ตํ•œ ๋ฐฉ์‹

์ „ํ†ต์  ๋งํฌ ๋ฐฉ์‹์€ ํ˜„์žฌ ํŽ˜์ด์ง€์—์„œ ์ˆ˜์‹ ๋œ html๋กœ ํ™”๋ฉด์„ ์ „ํ™˜ํ•˜๋Š” ๊ณผ์ •์—์„œ ์ „์ฒด ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ ๋ Œ๋”๋งํ•˜๊ฒŒ ๋˜๋ฏ€๋กœ ์ƒˆ๋กœ ๊ณ ์นจ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•œ ์›นํŽ˜์ด์ง€๋ผ๋ฉด ๋ฌธ์ œ ๋  ๊ฒƒ์ด ์—†๊ฒ ์ง€๋งŒ ๋ณต์žกํ•œ ์›นํŽ˜์ด์ง€์˜ ๊ฒฝ์šฐ, ์š”์ฒญ๋งˆ๋‹ค ์ค‘๋ณต๋œ HTML๊ณผ CSS, JavaScript๋ฅผ ๋งค๋ฒˆ ๋‹ค์šด๋กœ๋“œ ํ•ด์•ผํ•˜๋ฏ€๋กœ ์†๋„ ์ €ํ•˜์˜ ์š”์ธ์ด ๋ฉ๋‹ˆ๋‹ค.
์ด๋Ÿฌํ•œ ์ „ํ†ต์  ๋งํฌ ๋ฐฉ์‹์˜ ๋‹จ์ ์„ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด ๋“ฑ์žฅํ•œ ๊ฒƒ์ด AJAX(Asynchronous JavaScript and XML)์ž…๋‹ˆ๋‹ค. AJAX๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ด์šฉํ•ด์„œ ๋น„๋™๊ธฐ์ (Asynchronous)์œผ๋กœ ์„œ๋ฒ„์™€ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ํ†ต์‹  ๋ฐฉ์‹์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
AJAX๋ฅผ ํ†ตํ•œ ๋ฐฉ์‹์„ ์ด์šฉํ•˜๋ฉด ์ตœ์ดˆ์— ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์›นํŽ˜์ด์ง€๊ฐ€ ๋ฐ˜ํ™˜๋˜๋ฉด ์ดํ›„ ๋ถ€ํ„ฐ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›์œผ๋ฉฐ ํ™”๋ฉด์„ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.
์œ„ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด link tag(<a id="home">Home</a> ๋“ฑ)์— href ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚ด๋น„๊ฒŒ์ด์…˜์ด ํด๋ฆญ๋˜๋ฉด link tag์˜ ๊ธฐ๋ณธ ๋™์ž‘์„ preventํ•˜๊ณ  AJAX์„ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„์— ํ•„์š”ํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ•œํ›„ ์‘๋‹ต๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ด์šฉํ•˜์—ฌ html์„ ์™„์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ถˆํ•„์š”ํ•œ ๋ฆฌ์†Œ์Šค ์ค‘๋ณต ์š”์ฒญ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ํŽ˜์ด์ง€ ์ „์ฒด๋ฅผ ์ƒˆ๋กœ ๋ Œ๋”๋งํ•  ํ•„์š”๊ฐ€ ์—†๊ณ  ๊ฐฑ์‹ ์ด ํ•„์š”ํ•œ ์ผ๋ถ€๋งŒ ๋กœ๋“œํ•˜๋ฉด ๋˜๋ฏ€๋กœ ๋น ๋ฅธ ํผํฌ๋จผ์Šค์™€ ๋ถ€๋“œ๋Ÿฌ์šด ํ™”๋ฉด ํ‘œ์‹œ ํšจ๊ณผ๋ฅผ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ ์ด ๋ฐฉ์‹์€ URL์„ ๋ณ€๊ฒฝ์‹œํ‚ค์ง€ ์•Š์œผ๋ฏ€๋กœ ํ•ด๋‹น ํŽ˜์ด์ง€์˜ ์ฃผ์†Œ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ ๋’ค๋กœ๊ฐ€๊ธฐ, ์•ž์œผ๋กœ๊ฐ€๊ธฐ ๋“ฑ์˜ history ๊ด€๋ฆฌ๊ฐ€ ๋™์ž‘ํ•˜์ง€ ์•Š์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ฃผ์†Œ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๊ธฐ์— ์ƒˆ๋กœ๊ณ ์นจ์„ ํด๋ฆญํ•˜๋ฉด ์–ธ์ œ๋‚˜ ์ฒซํŽ˜์ด์ง€๊ฐ€ ๋‹ค์‹œ ๋กœ๋”ฉ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ๋˜ํ•œ SEO์— ์žˆ์–ด์„œ๋Š” ์ทจ์•ฝํ•œ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

3. Hash ๋ฐฉ์‹

AJAX ๋ฐฉ์‹์€ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ์†Œ์Šค ์ค‘๋ณต ์š”์ฒญ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๊ณ , ์ƒˆ๋กœ๊ณ ์นจ์ด ์—†๋Š” ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์ง€๋งŒ history ๊ด€๋ฆฌ๊ฐ€ ๋˜์ง€ ์•Š๋Š” ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ณด์™„ํ•œ ๋ฐฉ๋ฒ•์ด Hash๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.
Hash ๋ฐฉ์‹์€ URI์˜ fragment identifier(#service)์˜ ๊ณ ์œ  ๊ธฐ๋Šฅ์ธ ์•ต์ปค(anchor)๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
์œ„ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด link tag(<a href="#about">About</a> ๋“ฑ)์˜ href ์†์„ฑ์— hash๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ๋งํฌ๋ฅผ ํด๋ฆญํ•˜๋ฉด hash๊ฐ€ ์ถ”๊ฐ€๋œ URI๊ฐ€ ์ฃผ์†Œ์ฐฝ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด ๋•Œ URL์ด ๋™์ผํ•œ ์ƒํƒœ์—์„œ hash๊ฐ€ ๋ณ€๊ฒฝ๋˜๋„ ๋ธŒ๋ผ์šฐ์ €๋Š” ์„œ๋ฒ„์— ์›นํŽ˜์ด์ง€๋ฅผ ์š”์ฒญํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด hash๋Š” ์š”์ฒญ์„ ์œ„ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์•ต์ปค(anchor)๋กœ ์›นํŽ˜์ด์ง€ ๋‚ด๋ถ€์—์„œ ์ด๋™์„ ์œ„ํ•œ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ hash ๋ฐฉ์‹์€ ์„œ๋ฒ„์— ์ƒˆ๋กœ์šด ์š”์ฒญ์„ ๋ณด๋‚ด์ง€ ์•Š๊ณ , ๊ฐฑ์‹ ๋˜์ง€ ์•Š์ง€๋งŒ ํŽ˜์ด์ง€๋งˆ๋‹ค ๊ณ ์œ ์˜ ๋…ผ๋ฆฌ์  URL์ด ์กด์žฌํ•˜๋ฏ€๋กœ history๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
const root = document.querySelector(".container"); const routes = { "": "/data/home.json", service: "/data/service.json", about: "/data/about.html", }; const render = async () => { const hash = location.hash.replace("#", ""); const url = routes[hash]; const res = await fetch(url); const { title, content } = await res.json(); root.innerHTML = `<h1>${title}</h1><p>${content}</p>`; }; window.addEventListener("hashchange", render); window.addEventListener("DOMContentLoaded", render);
JavaScript
uri์˜ hash๊ฐ€ ๋ณ€๊ฒฝํ•˜๋ฉด ๋ฐœ์ƒํ•˜๋Š” ์ด๋ฒคํŠธ์ธ hashchange์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ hash์˜ ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•˜์—ฌ ํ•„์š”ํ•œ ์ถ”๊ฐ€์ ์ธ Ajax์š”์ฒญ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด hash ๋ฐฉ์‹์˜ ๋‹จ์ ์€ uri์— ๋ถˆํ•„์š”ํ•œ #์ด ๋“ค์–ด๊ฐ„๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ hash ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ๋•Œ #!์„ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ•˜๋Š”๋ฐ ์ด๋ฅผ ํ•ด์‹œ๋ฑ…(Hash-bang)์ด๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค. ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ๋Š” SEO ์ด์Šˆ์ž…๋‹ˆ๋‹ค. ๊ฒ€์ƒ‰์—”์ง„์€ ์›น์‚ฌ์ดํŠธ์˜ ์ฝ˜ํ…์ธ ๋ฅผ ์ˆ˜์ง‘ํ•˜๊ธฐ ์œ„ํ•ด ๋ณดํ†ต JavaScript๋ฅผ ์‹คํ–‰์‹œํ‚ค์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— hash ๋ฐฉ์‹์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ์‚ฌ์ดํŠธ์˜ ์ฝ˜ํ…์ธ ๋ฅผ ์ˆ˜์ง‘ํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๊ตฌ๊ธ€์€ ํ•ด์‹œ๋ฑ…์„ ์ผ๋ฐ˜ URL์„ ๋ณ€๊ฒฝ์‹œ์ผœ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์ง€๋งŒ, ๋‹ค๋ฅธ ๊ฒ€์ƒ‰ ์—”์ง„์€ hash ๋ฐฉ์‹์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ์‚ฌ์ดํŠธ์˜ ์ฝ˜ํ…์ธ ๋ฅผ ์ˆ˜์ง‘ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.

History Api๋ฅผ ์ด์šฉํ•œ PJAX

์œ„์—์„œ ์‚ดํŽด๋ณธ ๊ฒƒ์ฒ˜๋Ÿผ hash ๋ฐฉ์‹์˜ ๊ฐ€์žฅ ํฐ ๋‹จ์ ์€ SEO ์ด์Šˆ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ณด์™„ํ•œ ๋ฐฉ๋ฒ•์ด HTML5์˜ Histroy API์ธ pushState์™€ popstate ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ•œ PJAX ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.
์œ„ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด link tag(<a href="/service">Service</a> ๋“ฑ)์˜ href ์†์„ฑ์— path๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๋น„๊ฒŒ์ด์…˜์ด ํด๋ฆญ๋˜๋ฉด ํ•ด๋‹น ๋งํฌ์˜ path๊ฐ€ ์ถ”๊ฐ€๋œ URI๊ฐ€ ์„œ๋ฒ„๋กœ ์š”์ฒญ๋ฉ๋‹ˆ๋‹ค. PJAX ๋ฐฉ์‹์€ ์ด ๊ณผ์ •์—์„œ ๋‚ด๋น„๊ฒŒ์ด์…˜ ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ์บ์น˜ํ•˜๊ณ  preventDefault๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„์š”์ฒญ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„, href ์–ดํŠธ๋ฆฌ๋ทฐํŠธ์— path์„ ์‚ฌ์šฉํ•˜์—ฌ AJAX ์š”์ฒญ์„ ํ•ฉ๋‹ˆ๋‹ค.
์ด๋•Œ AJAX ์š”์ฒญ ์ž์ฒด๋Š” ์ฃผ์†Œ์ฐฝ์˜ URL์„ ๋ณ€๊ฒฝ์‹œํ‚ค์ง€ ์•Š์•„ history ๊ด€๋ฆฌ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด pushState ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค. pushState ๋ฉ”์„œ๋“œ๋Š” ์ฃผ์†Œ์ฐฝ์˜ URL์„ ๋ณ€๊ฒฝํ•˜๊ณ  URL์„ history entry๋กœ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
const root = document.querySelector(".container"); const navigation = document.getElementById("navigation"); const routes = { "/": "/data/home.json", "/service": "/data/service.json", "/about": "/data/about.html", }; const render = async (path) => { const url = routes[path]; const res = await fetch(url); const { title, content } = await res.json(); root.innerHTML = `<h1>${title}</h1><p>${content}</p>`; }; window.addEventListener("popstate", (e) => { render(e.state.path); }); navigation.addEventListener("click", (e) => { if (!e.target.matches("#navigation > li > a")) return; e.preventDefault(); const path = e.target.getAttribute("href"); history.pushState({ path }, null, path); render(path); }); // ์ตœ์ดˆ ์ดˆ๊ธฐํ™” ํŽ˜์ด์ง€ render("/");
JavaScript
PJAX ๋ฐฉ์‹์€ ์„œ๋ฒ„์— ์ƒˆ๋กœ์šด ์š”์ฒญ์„ ๋ณด๋‚ด์ง€ ์•Š์œผ๋ฉฐ ๋”ฐ๋ผ์„œ ํŽ˜์ด์ง€๊ฐ€ ์ƒˆ๋กœ๊ณ ์นจ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํŽ˜์ด์ง€๋งˆ๋‹ค ๊ณ ์œ ์˜ URL์ด ์กด์žฌํ•˜๋ฏ€๋กœ history๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ, ๋ธŒ๋ผ์šฐ์ €์˜ ์ƒˆ๋กœ๊ณ ์นจ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด https://localhost:8080/about์™€ ๊ฐ™์€ ์š”์ฒญ์ด ์„œ๋ฒ„๋กœ ์ „๋‹ฌ๋˜๋Š”๋ฐ. ์ด๋•Œ ์„œ๋ฒ„๋Š” URL์— ๋”ฐ๋ผ ํ•ด๋‹น ๋ฆฌ์†Œ์Šค๋ฅผ HTML๋กœ ํด๋ผ์ด์–ธํŠธ์— ์‘๋‹ตํ•ด์ฃผ์–ด์•ผ ์ตœ์ดˆ ํ™”๋ฉด์ด ํ‘œ์‹œ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ •๋ฆฌ

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

History API

ํžˆ์Šคํ† ๋ฆฌ API๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœ์ž๋Š” ์‚ฌ์šฉ์ž ํƒ์ƒ‰ ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Search
๋ฉ”์„œ๋“œ
์„ค๋ช…
forward()
Open
ํžˆ์Šคํ† ๋ฆฌ์—์„œ ๋‹ค์Œ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•œ๋‹ค
go(index)
Open
ํžˆ์Šคํ† ๋ฆฌ์—์„œ ํŠน์ • ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•œ๋‹ค
pushState(state, title, URL)
Open
ํžˆ์Šคํ† ๋ฆฌ ์Šคํƒ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘ธ์‹œํ•˜๊ณ  ์ œ๊ณต๋œ URL๋กœ ์ด๋™ํ•œ๋‹ค
replaceState(state, title, URL)
Open
ํžˆ์Šคํ† ๋ฆฌ ์Šคํƒ์—์„œ ๊ฐ€์žฅ ์ตœ๊ทผ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”๊พธ๊ณ  ์ œ๊ณต๋œ URL๋กœ ์ด๋™ํ•œ๋‹ค

๐Ÿ”— ์ฐธ๊ณ  ๋งํฌ

โ€ข