올바른 이해와 사용 방법
window.history.replaceState() 메서드는 새로운 페이지를 서버에 요청하지 않고 브라우저의 현재 활성화된 방문 기록 항목(entry)의 상태(State) 데이터와 URL을 새로운 값으로 교체(변경)합니다. 이때, 브라우저는 방문 기록(Session History)에 새로운 항목(entry)을 추가하지 않습니다.
참고하세요!
window.history.replaceState() 메서드는 줄여서 history.replaceState()라고만 작성하는 경우도 많습니다.
브라우저에서는 window 객체가 전역 객체이므로, window.history는 줄여서 history만으로도 동일하게 사용할 수 있습니다.
이 기능은 페이지를 새로고침하지 않고 화면의 일부만 변경하는 SPA(Single Page Application)에서 새로운 방문 기록 항목은 추가하지 않으면서 현재 활성화된 방문 기록 항목을 교체(변경)할 때(예: 검색 필터 적용, 탭 전환 등) 자주 사용됩니다.
특징
- 새로운 페이지를 서버에 요청하지 않고 현재 창이나 탭의 현재 활성화된 방문 기록 항목(entry)을 교체(변경)합니다.
- 방문 기록은 추가하지 않으면서 현재 활성화된 방문 기록(Session History)의 상태(State) 데이터를 업데이트할 때 유용합니다.
- 필요 시 URL도 교체(변경)할 수 있습니다.
- URL 교체(변경) 시 브라우저는
replaceState()호출 후 이 URL의 페이지를 새로 로드하지 않으며, 주소창의 URL만 교체(변경)됩니다. - 새로운 방문 기록 항목을 추가하지 않기 때문에 사용자가 "뒤로 가기" 버튼을 눌렀을 때, URL을 교체(변경)하기 전의 방문 기록 항목이 아닌 그 이전 방문 기록 항목으로 이동합니다.
구문
window 객체는 생략할 수 있으며, 보통 history.replaceState()를 사용합니다.
history.replaceState(state, unused)
history.replaceState(state, unused, url)
// 또는
window.history.replaceState(state, unused)
window.history.replaceState(state, unused, url)
매개변수
state |
|
|---|---|
unused |
이 매개변수는 역사적인 이유로 존재하며 현재는 사용되지 않습니다. 일반적으로 관례상 빈 문자열("")을 지정합니다. |
url |
|
반환 값
없습니다. 즉, undefined를 반환합니다.
기본 예제
이 예제는 https://www.example.com/에 접속한 사용자가 탭을 전환하는 상황을 가정합니다. 사용자가 "인기 콘텐츠" 버튼을 클릭했을 때, history.replaceState()를 사용해 전체 페이지를 새로고침하지 않고도 URL에 ?tab=popular를 붙여서 변경하고, 현재 방문 기록 항목의 상태(State) 데이터를 업데이트하는 과정을 보여줍니다.
<button type="button" onclick="replacePoularTab()">인기 콘텐츠</button>
function replacePoularTab() {
/* 초기 URL 예: https://www.example.com/ */
// 1. 교체(변경)할 상태(State) 데이터와 URL
const state = { currentTab: "popular" }; // 상태(State) 데이터
const url = "?tab=popular"; // URL
// 2. 현재 활성화된 방문 기록(Session History)의 상태(State) 데이터와 URL을 교체(변경)
history.replaceState(state, "", url);
// 3. 방문 기록 항목(entry)은 추가되지 않으면서 상태(State) 데이터와 주소창 URL 교체(변경)됨
// 주소창 결과는 : https://www.example.com/?tab=popular
// 상태(State) 데이터 확인
console.log("현재 상태 데이터:", history.state); // 출력: { currentTab: "popular" }
}
코드 부연설명
window.history.state 속성은 현재 창이나 탭의 브라우저 방문 기록에 저장된 상태(State) 데이터를 반환합니다.
참고하세요!
window.history.replaceState() 메서드는 줄여서 history.replaceState()라고만 작성하는 경우가 많은 것처럼
window.history.state 속성도 줄여서 history.state라고만 작성하는 경우도 많습니다.
사용법 참고 사항
replaceState()는 새로운 방문 기록 항목(entry)을 추가하지 않기 때문에 사용자가 '뒤로 가기' 버튼을 눌렀을 때, 교체(변경) 이전의 상태(State) 데이터로 돌아가지 않습니다.replaceState()는 페이지를 새로고침하지 않습니다. 현재 문서를 그대로 유지한 상태에서 새로운 방문 기록 항목(entry)은 추가되지 않으면서 상태(State) 데이터와 주소창의 URL만 교체(변경)됩니다.
활용 예제
상품 목록 페이지에서는 사용자가 정렬 기준이나 필터 조건을 변경하는 경우가 많습니다. 이때 정렬 기준 변경마다 새로운 방문 기록 항목(entry)을 추가하면 사용자가 '뒤로 가기' 버튼을 사용할 때 불필요한 이동 단계가 만들어질 수 있습니다.
이러한 경우 window.history.replaceState() 메서드를 사용하면 새로운 방문 기록 항목을 추가하지 않고 현재 활성화된 방문 기록 항목의 상태(State) 데이터와 URL을 업데이트할 수 있습니다.
다음 예제에서는 상품 정렬 기준을 변경할 때 replaceState()를 사용하여 현재 정렬 상태를 저장하고, 주소창의 URL도 함께 변경하는 방법을 알아봅니다.
<div class="sort-buttons">
<button type="button" onclick="changeSort('popular')">인기순</button>
<button type="button" onclick="changeSort('latest')">최신순</button>
<button type="button" onclick="changeSort('price_asc')">가격 낮은 순</button>
<button type="button" onclick="changeSort('price_desc')">가격 높은 순</button>
</div>
function changeSort(sortType) {
// 1. 현재 정렬 기준을 URL 쿼리 파라미터로 생성
const newUrl = `?sort=${sortType}`;
// 2. 새로운 방문 기록 항목을 추가하지 않고
// 현재 방문 기록 항목의 상태(State)와 URL을 교체
history.replaceState({ sort: sortType }, "", newUrl);
console.log(`현재 정렬 기준: ${sortType}`);
// 3. 실제 서비스에서는 이 위치에서
// 상품 목록 갱신 또는 정렬 처리 로직을 수행합니다.
// 예: updateProductList(sortType);
}
코드 부연설명
changeSort() 함수는 사용자가 상품 목록의 정렬 기준을 변경할 때 호출됩니다.
history.replaceState() 메서드는 새로운 방문 기록 항목(entry)을 추가하지 않고 현재 활성화된 방문 기록 항목의 상태(State) 데이터와 URL을 교체합니다.
예를 들어 사용자가 "가격 낮은 순" 버튼을 클릭하면
/products
/products?sort=price_asc
으로 주소창의 URL은 변경되지만, 브라우저 방문 기록에는 새로운 항목이 추가되지 않습니다.
따라서 사용자가 여러 번 정렬 기준을 변경하더라도 각 정렬 변경 과정이 방문 기록으로 남지 않으며, 사용자가 '뒤로 가기' 버튼을 눌렀을 때, 정렬 변경 전의 방문 기록 항목이 아닌 그 이전 방문 기록 항목으로 이동합니다.
주의할 점
window.history.replaceState() 메서드는 페이지를 새로 불러오지 않고 방문 기록 항목의 상태(State) 데이터와 URL을 변경할 수 있어 동적인 웹 페이지를 구현할 때 유용하게 활용되지만 구현 과정에서 몇 가지 주의할 점이 있습니다.
동일 출처 정책(Same-Origin Policy) 제한
replaceState(state, unused, url)에 전달하는 세 번째 매개변수(url)는 현재 페이지와 반드시 동일한 출처(도메인, 프로토콜, 포트)를 가져야 합니다. 동일하지 않은 출처 URL을 지정하면 SecurityError가 발생합니다.
SecurityError가 발생
/* 현재 페이지 URL 예: https://www.example.com/ */
history.replaceState({}, "", "https://www.cross-example.com/"); // 다른 도메인으로의 변경
상태(State) 데이터의 크기 및 종류 제한
replaceState(state, unused, url)에 전달하는 첫 번째 매개변수(state)는 새롭게 추가할 방문 기록에 저장할 상태(State) 데이터입니다. 객체(Plain objects, 일반 객체)뿐만 아니라 문자열, 숫자, 배열 등 구조화 가능한(Structured Clone) 자바스크립트 데이터라면 무엇이든 저장할 수 있습니다.
이때 전달하는 상태(State) 데이터는 브라우저가 방문 기록(Session History)과 함께 내부적으로 저장하며, 브라우저에 따라 크기 제한이 있습니다. 따라서 대용량 이미지 바이너리 데이터나 매우 큰 객체 또는 배열 등을 전달하면 예외가 발생할 수 있습니다.
또한 데이터가 DOM 요소나 함수, 순환 참조를 가진 객체 등인 경우는 구조화 가능한(Structured Clone) 데이터가 아니기 때문에 저장할 수 없습니다.
replaceState() 호출 자체는 popstate 이벤트를 발생시키지 않음
브라우저의 방문 기록(Session History)이 변경되어 이전 페이지 또는 다음 페이지로 이동할 때, 즉 현재 표시되고 있는 방문 기록 항목(현재 활성화된 항목)이 다른 항목으로 전환된 후 발생하는 이벤트가 popstate 이벤트입니다.
방문 기록이 변경될 때 발생하는 popstate 이벤트를 참조하세요.
브라우저의 방문 기록(Session History)에 replaceState() 호출로 새로운 방문 기록 항목(entry)을 추가하지 않으며, replaceState() 호출 자체는 popstate 이벤트를 발생시키지 않습니다. popstate 이벤트는 브라우저의 "뒤로 가기" 또는 "앞으로 가기" 탐색 등으로 현재 활성화된 방문 기록 항목(entry)이 다른 항목으로 변경될 때 발생합니다.
따라서 replaceState() 호출 후 사용자가 브라우저의 "뒤로 가기" 버튼을 눌러 다른 방문 기록 항목으로 이동하면 popstate 이벤트가 발생합니다.
뒤로가기 흐름의 변화
replaceState() 호출 후 사용자가 "뒤로가기 버튼"을 눌렀을 때 호출 전의 방문 기록 항목이 아닌 그 이전 방문 기록 항목으로 이동하므로 사용자 경험(UX) 흐름을 정교하게 설계해야 합니다.
새로고침 시 404 에러 (서버 설정 고려)
replaceState() 호출은 브라우저 주소창의 URL만 바꿀 뿐, 서버로 실제 요청을 보내지 않습니다. 하지만 사용자가 그 상태에서 새로고침(F5)을 하거나 해당 URL을 복사해 직접 주소창에 입력하고 접속하면, 브라우저는 변경된 URL에 해당하는 페이지를 서버에 요청합니다.
URL 경로가 /page-1에서 replaceState() 호출로 인해 /page-2로 변경되었다고 가정해 보겠습니다.
사용자가 변경된 경로로 직접 방문했을 때, 브라우저는 서버에 변경된 /page-2 경로를 가지고 있는 URL에 해당하는 페이지를 요청하게 됩니다. 이때, 실제 /page-2 에 해당하는 페이지가 없어 서버가 그 URL을 처리하지 못한다면 404 Not Found 에러가 발생합니다.
이런 상황은 replaceState() 호출로 인해 /page-2로 변경된 URL을 사용자가 그 상태에서 새로고침(F5)하는 경우에도 발생합니다.
따라서 이러한 점을 대비하여 서버 설정을 반드시 고려해야 합니다.
명세서
| 명세서 사양 | |
|---|---|
window.history.replaceState()
|
HTML #dom-history-replacestate-dev |
브라우저 호환성
| 메서드 |
데스크탑 Chrome
|
데스크탑 Edge
|
데스크탑 Firefox
|
Safari
|
|---|---|---|---|---|
window.history.replaceState()
|
5 | 12 | 4 | 5 |