history API로 SPA 구현

지인혁·2023년 10월 15일
1
post-custom-banner


history API

브라우저는 페이지 로딩 시 세션 히스토리를 갖는다. 세션 히스토리는 페이지를 이동할 때마다 쌓이며 이를 통해 뒤로가기 시 이전 페이지로 가거나 뒤로 간 이후 다시 앞으로 가는 등의 이동이 가능하다.

사용자가 페이지를 새로고침하거나 뒤로 가기/앞으로 가기 버튼을 클릭하지 않아도, 웹 애플리케이션 내에서 프로그래밍 방식으로 페이지 이동을 할 수 있다.

  • history.back() : 브라우저의 '뒤로' 버튼과 같은 역할. 세션 기록에서 한 단계 이전 페이지로 이동
  • history.forward() : 브라우저의 '앞으로' 버튼과 같은 역할. 세션 기록에서 한 단계 다음 페이지로 이동
  • history.go(n) : 현재 위치에서 상대적으로 n페이지만큼 앞이나 뒤로 이동. n이 음수일 경우 n페이지만큼 뒤로, 양수일 경우 n페이지만큼 앞으로 이동.

history API는 이러한 브라우저의 세션 기록을 조작할 수 있는 메소드를 담는 객체이며, history API를 활용하여 SPA를 구현할 수 있다.


pushState, replaceState

pushState는 세션 히스토리에 새 URL 상태를 쌓아 URL만 변경시키고 해당 URL로 요청은 하지 않는다. 또한 이전 페이지를 기억하여 돌아가게 할 수 있다.

replaceState는 세션 히스토리에 새 URL 상태를 쌓지 않아 이전 페이지를 기억하지 않고 이동할 URL을 변경시키고 해당 URL로 요청하지 않는다. 또한 뒤로가기를 하게 되면 이전 페이지로 가지 않고 히스토리에 저장된 제일 마지막 url로 이동한다.

위 함수들을 호출할 때 3가지 파라미터를 받는다.

  • state : history.state에서 꺼내쓸 수 있는 값
  • title : 변경될 페이지의 title을 가리키는 값, 대부분 브라우저가 지원하지 않아 빈 문자열을 넣으면 된다.
  • url : 세션 히스토리에 새로 넣을 url

pushState로 SPA 구현하기

SPA를 구한하기 앞서 중요한 포인트를 알아야 한다.

a태그, location.href로 url을 변경하는 것과 다르게 pushState는 url을 변경하지만 실제로는 url 텍스트만 변경되지 실제로 이동하여 GET 요청을 하지 않는다.

변경된 url에서 새로고침하면 당연히 해당 url은 존재하지 않고 접속하려하니 404에러가 발생하는 것이다.

코드 로직에 대한 설명은 밑에 작성하겠슴니다ㅎ

<body>
    <div id="container"></div>
    <a class="link-item" href="/product-list">product list</a>
    <a class="link-item" href="/article-list">article list</a>
</body>
<script>
    function router() {
        const $container = document.querySelector("#container");
        const { pathname } = location;

        if(pathname === "/") {
            $container.innerHTML = "<h1>HOME</h1>";
            console.log("home")
        }
        else if(pathname === "/product-list") {
            $container.innerHTML = "<h1>상품 목록</h1>";
            console.log("product")
        }
        else if(pathname === "/article-list") {
            $container.innerHTML = "<h1>게시글 목록</h1>"
            console.log("aritcle")
        }
        else {
            $container.innerHTML = "<h1>HOME</h1>";
            console.log("home 나머지")
        }
    }
    router();

    // 이벤트 버블링을 활용하여 window에 이벤트가 전파되면 새로고침을 막아준다.
    window.addEventListener("click", (e) => {
        // a태그가 클릭되면 일단 새로고침과 페이지 이동을 막는다.
        if(e.target.className === "link-item") {
            e.preventDefault(); 

            const { href } = e.target; // FULL URL이 반환된다.
            const path = href.replace(window.location.origin, ""); // URL 앞 부분을 날린다. location.origin은 앞 부분을 가지고 있다.

            history.pushState(null, null, path);
            router();
        }
    }) 
  // popstate 이벤트?? 뒤로가기나 앞으로갈때 발생하는 이벤트다.
    window.addEventListener("popstate", e => router())
</script>

최상위 window에서 a 태그를 클릭하게 되면 이벤트 버블링을 통해 관리하게 된다.

또한 router함수는 현재 url을 파싱하여 파싱된 url을 분석하여 어느 페이지를 보여줄지 관리하는 곳이다.

만약 a 태그를 클릭하게 되면 이동할 url을 pushState를 호출하여 url 값만 바꿔주고 router 함수를 통해 현재 url을 분석하여 어떤 페이지를 보여줄지 결정한다.

또한 사용자가 뒤로가기, 앞으로가기 버튼을 클릭하게 되면 pushState을 통해 세션 히스토리에 저장된 순서대로 이동하며 이동한 페이지의 url로 get 요청을 하게 된다.

이때 실제로 해당 url은 존재하지 않는다. 그래서 따로 처리를 하지 않았다면 404에러나, 에러를 발생한다.

이때 사용하는 방법이 popstate을 통해 뒤로가기 앞으로가기 이벤트를 감지하여 router 함수를 호출해주기만 에러가 발생하지 않고 현재 url을 분석하여 알맞는 페이지를 보여줌으로써 해결된다.


profile
대구 사나이
post-custom-banner

0개의 댓글