Front-end

[WEB] History API: ํ˜„๋Œ€ ์›น์˜ ๋’ค๋ ์ด์•ผ๊ธฐ ๐Ÿ“œ

xeunnie 2024. 12. 28. 01:00
728x90
๋ฐ˜์‘ํ˜•

๐Ÿ“œ History API ํ†บ์•„๋ณด๊ธฐ!

์—ฌ๋Ÿฌ๋ถ„, ๋ธŒ๋ผ์šฐ์ €์—์„œ “๋’ค๋กœ ๊ฐ€๊ธฐ” ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅธ ๊ฒฝํ—˜ ๋‹ค๋“ค ์žˆ์ฃ ? ๋ฐ”๋กœ ๊ทธ ์ˆœ๊ฐ„, ์šฐ๋ฆฌ๊ฐ€ ๋ณ„์ƒ๊ฐ ์—†์ด ๋ˆ„๋ฅธ ๋ฒ„ํŠผ ๋’ค์—๋Š” History API๋ผ๋Š” ๋˜‘๋˜‘ํ•œ ๋…€์„์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด API๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ํŽ˜์ด์ง€ ์ด๋™์„ ์ œ์–ดํ•˜๊ณ , ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์˜ˆ์š”. ์˜ค๋Š˜์€ History API์˜ ๊ธฐ๋ณธ ๊ฐœ๋…, ์‚ฌ์šฉ๋ฒ•, ๊ทธ๋ฆฌ๊ณ  ์‹ค๋ฌด์—์„œ ์•Œ์•„๋‘๋ฉด ์ข‹์€ ํŒ๋“ค์„ ํŒŒํ—ค์ณ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿš€


๐Ÿ’พ History API๋ž€?

History API๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ ์„ธ์…˜ ํžˆ์Šคํ† ๋ฆฌ(๋ฐฉ๋ฌธ ๊ธฐ๋ก)๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋ธŒ๋ผ์šฐ์ € ๋‚ด์žฅ API์ž…๋‹ˆ๋‹ค. ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•˜์ง€ ์•Š๊ณ ๋„ URL์„ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜, ์‚ฌ์šฉ์ž์˜ ๋’ค๋กœ/์•ž์œผ๋กœ ์ด๋™ ๊ฐ™์€ ํ–‰๋™์„ ์ปจํŠธ๋กคํ•  ์ˆ˜ ์žˆ์–ด์š”. ํŠนํžˆ, SPA(Single Page Application)์—์„œ๋Š” ๊ฑฐ์˜ ํ•„์ˆ˜๋กœ ์‚ฌ์šฉ๋˜์ฃ .


๐Ÿ”‘ ํ•ต์‹ฌ ๋ฉ”์„œ๋“œ์™€ ์†์„ฑ

1. window.history.length

ํ˜„์žฌ ๋ธŒ๋ผ์šฐ์ € ์„ธ์…˜ ํžˆ์Šคํ† ๋ฆฌ์˜ ๊ธธ์ด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž๊ฐ€ ์„ธ ํŽ˜์ด์ง€๋ฅผ ๋ฐฉ๋ฌธํ–ˆ๋‹ค๋ฉด history.length๋Š” 3์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

console.log(window.history.length); // ์„ธ์…˜ ํžˆ์Šคํ† ๋ฆฌ์˜ ๊ธธ์ด ์ถœ๋ ฅ

2. window.history.back()

๋ธŒ๋ผ์šฐ์ € ํžˆ์Šคํ† ๋ฆฌ์—์„œ ์ด์ „ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €์˜ “๋’ค๋กœ ๊ฐ€๊ธฐ” ๋ฒ„ํŠผ๊ณผ ๋™์ผํ•œ ๊ธฐ๋Šฅ์ด์—์š”.

history.back(); // ์ด์ „ ํŽ˜์ด์ง€๋กœ ์ด๋™

 

3. window.history.forward()

ํžˆ์Šคํ† ๋ฆฌ์—์„œ ๋‹ค์Œ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. “์•ž์œผ๋กœ ๊ฐ€๊ธฐ” ๋ฒ„ํŠผ๊ณผ ๋™์ผํ•˜์ฃ .

history.forward(); // ๋‹ค์Œ ํŽ˜์ด์ง€๋กœ ์ด๋™

 

4. window.history.go(n)

  • ํžˆ์Šคํ† ๋ฆฌ๋ฅผ n๋ฒˆ์งธ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
  • n > 0: ์•ž์œผ๋กœ ์ด๋™
  • n < 0: ๋’ค๋กœ ์ด๋™
  • n === 0: ํ˜„์žฌ ํŽ˜์ด์ง€ ์ƒˆ๋กœ๊ณ ์นจ
history.go(-2); // ๋‘ ํŽ˜์ด์ง€ ๋’ค๋กœ ์ด๋™
history.go(2);  // ๋‘ ํŽ˜์ด์ง€ ์•ž์œผ๋กœ ์ด๋™

โœจ History API์˜ ํ™•์žฅ๋œ ๊ธฐ๋Šฅ

ํ˜„๋Œ€ ์›น์—์„œ๋Š” ๋‹จ์ˆœํžˆ ๋’ค๋กœ/์•ž์œผ๋กœ ์ด๋™ํ•˜๋Š” ๊ธฐ๋Šฅ๋งŒ์œผ๋กœ๋Š” ๋ถ€์กฑํ•˜์ฃ . ๊ทธ๋ž˜์„œ History API๋Š” SPA์˜ ๋ผ์šฐํŒ…์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด ๋” ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

 

1. history.pushState()

URL์„ ๋ณ€๊ฒฝํ•˜๋ฉด์„œ ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ํžˆ์Šคํ† ๋ฆฌ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•˜์ง€ ์•Š๊ณ ๋„ ์ฃผ์†Œ ํ‘œ์‹œ์ค„์˜ URL์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์–ด์š”.

history.pushState({ page: 1 }, "Title 1", "/page1");
console.log(location.pathname); // "/page1"

 

๋งค๊ฐœ๋ณ€์ˆ˜ ์„ค๋ช…

  1. state: ํŽ˜์ด์ง€์™€ ์—ฐ๊ฒฐํ•  ๋ฐ์ดํ„ฐ ๊ฐ์ฒด. (์‚ฌ์šฉ์ž๊ฐ€ ์ •์˜)
  2. title: ๋ธŒ๋ผ์šฐ์ € ํƒญ์˜ ์ œ๋ชฉ. (๋Œ€๋ถ€๋ถ„ ๋ฌด์‹œ๋จ)
  3. url: ๋ณ€๊ฒฝํ•  URL.

2. history.replaceState()

ํ˜„์žฌ ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ์ƒˆ๋กœ์šด ์ƒํƒœ๋กœ ๊ต์ฒดํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ์กด์˜ ๊ธฐ๋ก์„ ๋ฎ์–ด์“ฐ๋ฏ€๋กœ ๋’ค๋กœ ๊ฐ€๊ธฐ ์‹œ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์•„์š”.

history.replaceState({ page: 2 }, "Title 2", "/page2");
console.log(location.pathname); // "/page2"

๐Ÿ”„ popstate ์ด๋ฒคํŠธ

URL ๋ณ€๊ฒฝ ์‹œ ํžˆ์Šคํ† ๋ฆฌ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด popstate ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด ์ด๋ฒคํŠธ๋Š” ๋’ค๋กœ ๊ฐ€๊ธฐ๋‚˜ ์•ž์œผ๋กœ ๊ฐ€๊ธฐ ๊ฐ™์€ ๋™์ž‘์„ ๊ฐ์ง€ํ•  ๋•Œ ์œ ์šฉํ•ด์š”.

window.addEventListener("popstate", (event) => {
  console.log("Popstate ๋ฐœ์ƒ:", event.state);
});

๐Ÿšง ์‚ฌ์šฉ ์‹œ ์ฃผ์˜ํ•  ์ 

  1. URL ๋ณ€๊ฒฝ์ด ์„œ๋ฒ„ ์š”์ฒญ์œผ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Œ
    • History API๋กœ URL์„ ๋ณ€๊ฒฝํ–ˆ๋”๋ผ๋„, ์„œ๋ฒ„๋Š” ์ด๋ฅผ ๋ชจ๋ฆ…๋‹ˆ๋‹ค. ์ƒˆ๋กœ๊ณ ์นจ ์‹œ 404 ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์–ด์š”.
    • ํ•ด๊ฒฐ์ฑ…: ์„œ๋ฒ„์—์„œ SPA์˜ ๊ธฐ๋ณธ HTML ํŒŒ์ผ์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์„ค์ •ํ•˜์„ธ์š”.
  2. State ๊ฐ์ฒด ๊ด€๋ฆฌ
    • pushState๋‚˜ replaceState์˜ state ๊ฐ์ฒด๋Š” ๋ธŒ๋ผ์šฐ์ € ํžˆ์Šคํ† ๋ฆฌ์™€ ํ•จ๊ป˜ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ๋„ˆ๋ฌด ํฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์œผ๋ฉด ์„ฑ๋Šฅ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์–ด์š”.
  3. SEO ๋ฌธ์ œ
    • History API๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ๋งŒ ์ž‘๋™ํ•˜๋ฏ€๋กœ ๊ฒ€์ƒ‰ ์—”์ง„ ๋ด‡์€ ์ œ๋Œ€๋กœ ๋ Œ๋”๋งํ•˜์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด SSR(Server-Side Rendering)์ด๋‚˜ Prerendering์„ ๊ณ ๋ คํ•˜์„ธ์š”.

๐Ÿ›  ์‹ค๋ฌด ์˜ˆ์ œ: ๊ฐ„๋‹จํ•œ SPA ๋ผ์šฐํ„ฐ ๋งŒ๋“ค๊ธฐ

History API๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ„๋‹จํ•œ SPA ๋ผ์šฐํ„ฐ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊นŒ์š”?

const routes = {
  "/": "<h1>Home</h1>",
  "/about": "<h1>About</h1>",
  "/contact": "<h1>Contact</h1>",
};

// ํŽ˜์ด์ง€ ๋ Œ๋”๋ง ํ•จ์ˆ˜
function render(path) {
  document.body.innerHTML = routes[path] || "<h1>404 Not Found</h1>";
}

// ์ดˆ๊ธฐ ๋กœ๋“œ
render(location.pathname);

// ๋งํฌ ํด๋ฆญ ์‹œ URL ๋ณ€๊ฒฝ ๋ฐ ํŽ˜์ด์ง€ ๋ Œ๋”๋ง
document.addEventListener("click", (e) => {
  if (e.target.tagName === "A") {
    e.preventDefault();
    const path = e.target.getAttribute("href");
    history.pushState(null, "", path);
    render(path);
  }
});

// ๋’ค๋กœ/์•ž์œผ๋กœ ์ด๋™ ์‹œ ๋ Œ๋”๋ง
window.addEventListener("popstate", () => {
  render(location.pathname);
});

 

HTML ์ฝ”๋“œ

<nav>
  <a href="/">Home</a>
  <a href="/about">About</a>
  <a href="/contact">Contact</a>
</nav>

๐ŸŽฏ History API๊ฐ€ ๊ฐ€์ ธ๋‹ค์ฃผ๋Š” ์ด์ 

  1. SPA ๋ผ์šฐํŒ…์˜ ํ•„์ˆ˜ ์š”์†Œ: URL์„ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด์„œ๋„ ํŽ˜์ด์ง€ ์ƒˆ๋กœ๊ณ ์นจ ์—†์ด ์ฝ˜ํ…์ธ ๋ฅผ ์—…๋ฐ์ดํŠธ
  2. ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ๊ฐœ์„ : ๋ธŒ๋ผ์šฐ์ €์˜ “๋’ค๋กœ/์•ž์œผ๋กœ ๊ฐ€๊ธฐ” ๋ฒ„ํŠผ์„ ํ†ตํ•ด๋„ ์ž์—ฐ์Šค๋Ÿฌ์šด ๋™์ž‘ ์œ ์ง€
  3. ์„œ๋ฒ„ ๋ถ€ํ•˜ ๊ฐ์†Œ: ํด๋ผ์ด์–ธํŠธ์—์„œ URL์„ ์ œ์–ดํ•˜๋ฏ€๋กœ ์„œ๋ฒ„์™€์˜ ํ†ต์‹ ์„ ์ตœ์†Œํ™”

๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ ๐Ÿ”–

History API๋Š” ๋ธŒ๋ผ์šฐ์ € ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ธฐ๋ณธ์ ์ธ ๊ธฐ๋Šฅ์—์„œ ๋‚˜์•„๊ฐ€, SPA์™€ ๊ฐ™์€ ํ˜„๋Œ€์ ์ธ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐ ํ•ต์‹ฌ์ ์ธ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์˜ค๋Š˜ ๋ฐฐ์šด ๋‚ด์šฉ์„ ํ†ตํ•ด ๋ธŒ๋ผ์šฐ์ € ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ์ž์œ ์ž์žฌ๋กœ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋Š” ์ „์„ค์˜ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์–ด๋ณด์„ธ์š”. ๐Ÿ˜Š

 

๐ŸŒท์ „์„ค์˜ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์–ด๋ด…์‹œ๋‹น! ๐ŸŒท

728x90
๋ฐ˜์‘ํ˜•