History API

Jungwon Lee(Jenny)·2021년 5월 8일
1
post-thumbnail

이 글은 아래 [참고]에 작성한 블로그들을 보고 공부한 내용을 기록한 글입니다.

history

DOM의 window 객체는 history 객체를 통해 브라우저의 히스토리에 접근할 수 있다.

예를들면 아래와 같이 back(), forward(), go() 메서드를 이용하여 브라우저의 이전페이지, 다음페이지 기능을 구현할 수 있다.

// 뒤로가기
window.histroy.back();
 
// 앞으로가기
window.histroy.forward();
 
//back()과 동일하게 한 페이지 뒤로 이동
window.history.go(-1);

//forward()와 동일하게 한 페이지 앞으로 이동
window.history.go(1);

// 두 페이지 이전으로 이동
window.history.go(-2);

//length속성을 이용하여 몇페이지가 쌓여있는지 알 수 있다
window.history.length;
//현재페이지를 기준으로 앞, 뒤 페이지가 없다면 1이 출력된다.

히스토리 추가 및 변경

history 내역은 하나의 목록이다. 뒤로가기, 앞으로가기는 목록 안에서 이동하는 것이다. 따라서 목록에 새로운 주소를 추가하면 페이지를 이동한 셈이 된다. 그 목록에 주소를 추가하기 위한 메소드가 HTML5에서 생겼는데, 바로 history.pushState()history.replaceState()이다.

history.pushState({data: 'pushState1'}, '', '/pushState1');
history.replaceState({data: 'replaceState'}, '', '/replace-state');

첫번째 파라미터는 history.state에 기록할 데이터다. 두번째 인자는 바꿀 제목 그리고 세번째 인자는 바뀔 주소이다.

아래의 코드로 공부를 해보자.

<!DOCTYPE html>
<html lang="ko">
  <head>
    <title>History API Sample</title>
    <meta charset="utf-8" />
    <style>
      section {
        margin: 20px 0;
      }
    </style>
  </head>
  <body>
    <section>
      <h2>push state</h2>
      <button id="push-state1">pushState1</button>
      <button id="push-state2">pushState2</button>
      <button id="push-state3">pushState3</button>
    </section>
    <section>
      <h2>replace state</h2>
      <button id="replace-state">replaceState</button>
    </section>
    <section>
      <h2>history state</h2>
      <span id="state"></span>
    </section>
    <script>
      const currentHistoryState = () => {
        document.getElementById("state").innerText = JSON.stringify(
          history.state
        );
      };

      currentHistoryState();

      // pushState()
      document.getElementById("push-state1").addEventListener("click", () => {
        history.pushState({ data: "pushState1" }, "", "/push-state1");
        currentHistoryState();
      });

      document.getElementById("push-state2").addEventListener("click", () => {
        history.pushState({ data: "pushState2" }, "", "/push-state2");
        currentHistoryState();
      });

      document.getElementById("push-state3").addEventListener("click", () => {
        history.pushState({ data: "pushState3" }, "", "/push-state3");
        currentHistoryState();
      });

      // replaceState()
      document.getElementById("replace-state").addEventListener("click", () => {
        history.replaceState({ data: "replaceState" }, "", "/replace-state");
        currentHistoryState();
      });

      // 브라우저의 뒤로가기 / 앞으로가기를 누르면 history state 값을 확인하여 출력합니다.
      window.addEventListener("popstate", () => {
        currentHistoryState();
      });
    </script>
  </body>
</html>

코드는 이 👉블로그 의 주인분이 쓰신 코드다.

처음 창을 열었을 땐 아래와 같은 상태가 뜬다

이때 pushState 1, 2, 3을 순서대로 누르면


이렇게 아래와같이 잘 바뀐다. 게다가 뒤로가기가 잘 활성화 되어있다.

그럼 다시 라이브서버를 켜서 replaceState버튼을 눌러보자.

주의깊게 볼 부분: replaceState를 눌렀을 때 url부분과 아래의 history.state는 잘 변경 되지만, 뒤로가기 버튼이 비활성화 되어있다.

이는, pushState는 주소목록에 새로운 주소를 추가하며, 방금까지 있던 주소를 이전 주소로 두고 새로운 주소로 /pushState 를 추가한 것이다. 그래서 이전 주소가 남아있기 때문에 뒤로가기를 통해 이전 주소로 넘어갈 수 있었다.

하지만 replaceState는 이전 주소를 없애고 바꿀 주소를 넣는다. 즉 새로운 엔트리를 추가하지 않고, 현재의 엔트리 값을 변경하기 때문에 뒤로가기로 이전 URL로 이동할 수 없다.

좀 더 자세히 풀어서 설명하자면,

  1. pushState()클릭 ⇒ URL이 /push-state1 로 변경 -> pushState2 클릭 -> URL이 /push-state2 로 변경 -> 브라우저의 뒤로가기 누르면 -> URL이 /push-state1 로 변경
  2. pushState1 클릭 -> URL이 /push-state1 로 변경 -> pushState2 클릭 -> URL이 /push-state2 로 변경 -> replace-state 클릭 -> URL이 /replace-state 로 변경 -> 브라우저의 뒤로가기 누르면 -> URL이 /push-state1 로 변경



pushState, replaceState로 주소를 바꾼 후, 뒤로가기나 앞으로가기를 누르면 popstate이벤트가 발생한다. 위의 코드처럼 윈도우에 이벤트 리스너를 연결해 두면 뒤로가기나 앞으로가기를 눌렀을 때 이벤트가 발생한다.

그렇기에 popstate이벤트 발생 후 history.state에 접근하면 이전 state를 가져올 수 있다.따라서 이전 페이지도 그 정보들을 활용하여 다시 렌더링 할 수 있다.

popstate 이벤트는 활성화된 히스토리 엔트리에 변화가 있을 때마다 발생된다. 발생 시 전달되는 state속성은 state object의 사본이 된다. 그로인해, 뒤로 가기의 상황에서 서버 요청 없이 이전 목록의 화면을 보여주는 것과 같은 처리를 할 수 있다.

window.addEventListener("popstate",(e)=>{
	let copyState=e.state;
    output.innerHTML=copyState.content
})

주의할 점은 history.pushState() 또는 history.replaceState()를 호출한다고, popstate이벤트가 트리거 되지는 않는다. 뒤로가기, 앞으로 가기 버튼 또는 history.back(), forward()과 같은 자바스크립트를 통한 호출에 의해서만 트리거가 발생한다.

또한 새로고침을 눌렀을 경우에는 없는 페이지라고 뜨기 때문에 이 부분은 서버사이드 렌더링으로 해결해야한다.


참고:

히스토리API 블로그 글1

히스토리API 블로그 글2

히스토리API 블로그 글3

profile
FE개발자가 되고싶은 말하는 감자

1개의 댓글

comment-user-thumbnail
2022년 7월 2일

링크해갑니다~버튼을 누르지 않고 해당 페이지로 접속했을때 url이 바뀌는 방법은 없을까요?

답글 달기