๐ 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"
๋งค๊ฐ๋ณ์ ์ค๋ช
- state: ํ์ด์ง์ ์ฐ๊ฒฐํ ๋ฐ์ดํฐ ๊ฐ์ฒด. (์ฌ์ฉ์๊ฐ ์ ์)
- title: ๋ธ๋ผ์ฐ์ ํญ์ ์ ๋ชฉ. (๋๋ถ๋ถ ๋ฌด์๋จ)
- 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);
});
๐ง ์ฌ์ฉ ์ ์ฃผ์ํ ์
- URL ๋ณ๊ฒฝ์ด ์๋ฒ ์์ฒญ์ผ๋ก ์ด์ด์ง ์ ์์
- History API๋ก URL์ ๋ณ๊ฒฝํ๋๋ผ๋, ์๋ฒ๋ ์ด๋ฅผ ๋ชจ๋ฆ ๋๋ค. ์๋ก๊ณ ์นจ ์ 404 ์๋ฌ๊ฐ ๋ฐ์ํ ์ ์์ด์.
- ํด๊ฒฐ์ฑ : ์๋ฒ์์ SPA์ ๊ธฐ๋ณธ HTML ํ์ผ์ ๋ฐํํ๋๋ก ์ค์ ํ์ธ์.
- State ๊ฐ์ฒด ๊ด๋ฆฌ
- pushState๋ replaceState์ state ๊ฐ์ฒด๋ ๋ธ๋ผ์ฐ์ ํ์คํ ๋ฆฌ์ ํจ๊ป ์ ์ฅ๋ฉ๋๋ค. ๋๋ฌด ํฐ ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ผ๋ฉด ์ฑ๋ฅ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ด์.
- 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๊ฐ ๊ฐ์ ธ๋ค์ฃผ๋ ์ด์
- SPA ๋ผ์ฐํ ์ ํ์ ์์: URL์ ๋์ ์ผ๋ก ๋ณ๊ฒฝํ๋ฉด์๋ ํ์ด์ง ์๋ก๊ณ ์นจ ์์ด ์ฝํ ์ธ ๋ฅผ ์ ๋ฐ์ดํธ
- ์ฌ์ฉ์ ๊ฒฝํ ๊ฐ์ : ๋ธ๋ผ์ฐ์ ์ “๋ค๋ก/์์ผ๋ก ๊ฐ๊ธฐ” ๋ฒํผ์ ํตํด๋ ์์ฐ์ค๋ฌ์ด ๋์ ์ ์ง
- ์๋ฒ ๋ถํ ๊ฐ์: ํด๋ผ์ด์ธํธ์์ URL์ ์ ์ดํ๋ฏ๋ก ์๋ฒ์์ ํต์ ์ ์ต์ํ
๋ง๋ฌด๋ฆฌํ๋ฉฐ ๐
History API๋ ๋ธ๋ผ์ฐ์ ํ์คํ ๋ฆฌ๋ฅผ ๊ด๋ฆฌํ๋ ๊ธฐ๋ณธ์ ์ธ ๊ธฐ๋ฅ์์ ๋์๊ฐ, SPA์ ๊ฐ์ ํ๋์ ์ธ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ํต์ฌ์ ์ธ ์ญํ ์ ํฉ๋๋ค. ์ค๋ ๋ฐฐ์ด ๋ด์ฉ์ ํตํด ๋ธ๋ผ์ฐ์ ํ์คํ ๋ฆฌ๋ฅผ ์์ ์์ฌ๋ก ๋ค๋ฃฐ ์ ์๋ ์ ์ค์ ๊ฐ๋ฐ์๊ฐ ๋์ด๋ณด์ธ์. ๐
๐ท์ ์ค์ ๊ฐ๋ฐ์๊ฐ ๋์ด๋ด ์๋น! ๐ท