히스토리 API (Browser History API)
브라우저에서 페이지 이동 없이 URL을 조작하고 기록을 관리하려면 History API가 큰 도움이 된다. SPA(싱글 페이지 애플리케이션)에서 자연스러운 네비게이션을 구현할 때 특히 유용하다. 이번에는 History API의 기본부터 심화 활용까지 코드와 함께 자세히 알아보려고 한다.
History API를 잘 활용하면 사용자 경험을 개선하고, 페이지 새로고침 없이도 깔끔한 상태 관리가 가능하다. 하나씩 차근차근 살펴보자.
History API 기본
window.history
객체를 통해 브라우저 기록을 다룰 수 있다. 가장 기본적인 메서드부터 보자:
console.log(window.history.length);
// 현재 세션의 기록 수 출력
history.back();
// 이전 페이지로 이동
history.forward();
// 다음 페이지로 이동
history.go(-2);
// 기록에서 두 단계 뒤로 이동
back
, forward
, go
로 기록을 이동할 수 있다. 단순하지만 강력한 기능이다.
1. pushState로 기록 추가
pushState
를 사용하면 페이지 새로고침 없이 URL을 변경하고 기록을 추가할 수 있다:
history.pushState(
{ page: "home" }, // 상태 객체
"홈", // 제목 (현재는 무시됨)
"/home" // URL
);
console.log(history.state);
// { page: "home" }
console.log(window.location.pathname);
// "/home"
URL이 /home
으로 바뀌었지만 페이지는 새로고침되지 않았다. 상태 객체는 나중에 유용하게 쓰인다.
2. replaceState로 기록 수정
replaceState
는 새 기록을 추가하지 않고 현재 기록을 수정한다:
history.pushState({ page: "about" }, "소개", "/about");
history.replaceState({ page: "about-updated" }, "소개 수정", "/about-us");
console.log(history.state);
// { page: "about-updated" }
console.log(location.pathname);
// "/about-us"
pushState
로 기록이 추가된 후, replaceState
로 현재 상태와 URL을 업데이트했다.
3. popstate 이벤트로 상태 감지
사용자가 뒤로 가기나 앞으로 가기를 누르면 popstate
이벤트가 발생한다:
window.addEventListener("popstate", (event) => {
if (event.state) {
console.log("상태: ", event.state);
} else {
console.log("상태 없음");
}
});
history.pushState({ page: "profile" }, "프로필", "/profile");
history.pushState({ page: "settings" }, "설정", "/settings");
history.back();
// "상태: { page: 'profile' }"
뒤로 가기를 눌렀을 때 이전 상태를 감지해서 로그로 출력했다.
4. 간단한 SPA 구현
History API로 간단한 SPA 네비게이션을 만들어보자:
const content = document.createElement("div");
document.body.appendChild(content);
function renderPage(state) {
const page = state ? state.page : "home";
content.innerHTML = `현재 페이지: ${page}`;
}
window.addEventListener("popstate", (event) => {
renderPage(event.state);
});
const links = [
{ path: "/home", state: { page: "home" } },
{ path: "/about", state: { page: "about" } },
{ path: "/contact", state: { page: "contact" } }
];
links.forEach((link) => {
const a = document.createElement("a");
a.href = link.path;
a.textContent = link.state.page;
a.addEventListener("click", (e) => {
e.preventDefault();
history.pushState(link.state, "", link.path);
renderPage(link.state);
});
document.body.appendChild(a);
document.body.appendChild(document.createElement("br"));
});
renderPage(history.state);
링크를 클릭하면 URL이 바뀌고 콘텐츠가 업데이트된다. 뒤로 가기와 앞으로 가기도 자연스럽게 동작한다.
5. 쿼리 파라미터와 조합
URL에 쿼리 파라미터를 추가해서 상태를 더 풍성하게 관리할 수 있다:
function renderContent(state, search) {
const params = new URLSearchParams(search);
const id = params.get("id") || "없음";
console.log(`페이지: ${state.page}, ID: ${id}`);
}
window.addEventListener("popstate", (event) => {
renderContent(event.state, location.search);
});
history.pushState(
{ page: "product" },
"",
"/product?id=123"
);
// "페이지: product, ID: 123"
history.pushState(
{ page: "product" },
"",
"/product?id=456"
);
// "페이지: product, ID: 456"
history.back();
// "페이지: product, ID: 123"
쿼리 파라미터를 활용해서 상태에 추가 정보를 담았다.
6. 동적 라우팅 처리
경로에 동적인 값을 넣어서 라우팅처럼 사용할 수 있다:
function getPageFromPath(pathname) {
const match = pathname.match(/\/user\/(\d+)/);
if (match) {
return { page: "user", id: match[1] };
}
return { page: "home" };
}
function render(state) {
console.log(`페이지: ${state.page}, ID: ${state.id || '없음'}`);
}
window.addEventListener("popstate", (event) => {
const state = event.state || getPageFromPath(location.pathname);
render(state);
});
history.pushState(
{ page: "user", id: "100" },
"",
"/user/100"
);
// "페이지: user, ID: 100"
history.pushState(
{ page: "user", id: "200" },
"",
"/user/200"
);
// "페이지: user, ID: 200"
history.back();
// "페이지: user, ID: 100"
정규식을 사용해서 동적 경로를 파싱하고 상태를 생성했다.
7. 상태 복원과 초기화
페이지를 새로고침했을 때도 상태를 복원할 수 있다:
function initPage() {
const state = history.state || getPageFromPath(location.pathname);
render(state);
}
window.addEventListener("popstate", (event) => {
render(event.state);
});
history.pushState({ page: "settings" }, "", "/settings");
initPage();
// "페이지: settings, ID: 없음"
새로고침 후에도 history.state
나 경로를 통해 상태를 복원했다.
8. 성능과 사용자 경험에 미치는 영향
History API가 코드와 사용자 경험에 어떤 영향을 주는지 보자:
- 성능: 페이지 새로고침 없이 상태를 변경하니 로드가 빠르다.
- 사용자 경험: 자연스러운 네비게이션과 뒤로 가기 지원으로 편리함이 커진다.
pushState와 popstate를 조화롭게 사용하면 SPA의 핵심 흐름을 만들 수 있다.
마무리
History API는 URL과 브라우저 기록을 유연하게 다룰 수 있게 해준다. 기본 메서드부터 동적 라우팅, 상태 복원까지 활용하면 SPA를 비롯한 다양한 환경에서 강력한 도구가 된다.
'코딩 공부 > 자바스크립트' 카테고리의 다른 글
71. 자바스크립트 Canvas API (2) | 2025.03.24 |
---|---|
70. 자바스크립트 Fetch API 심화 (Advanced Fetch API) (1) | 2025.03.23 |
68. 자바스크립트 비동기 타임아웃 관리 (Managing Async Timeouts) (1) | 2025.03.23 |
67. 자바스크립트 async/await 최적화 (Optimizing Async/Await) (1) | 2025.03.22 |
66. 자바스크립트 프로미스 병렬 처리 심화 (Advanced Promise Parallelism) (1) | 2025.03.22 |