JS SPA(Single Page Application)

정현승·2024년 11월 8일

SPA

SPA는 브라우저에서 한 페이지로 동작하며, 페이지 전환 시 전체 페이지를 새로고침하지 않고 부분적으로 변경합니다.

History

History API는 JavaScript에서 SPA의 라우팅을 더 세밀하게 제어하고, 브라우저의 기본적인 탐색 기능(뒤로 가기, 앞으로 가기)을 활용할 수 있게 해줍니다.

history.pushState(state, "", url)

  • 새로운 상태를 기록하고 URL을 변경합니다.
  • 페이지를 새로고침하지 않고, 브라우저의 뒤로 가기/앞으로 가기 기능으로 이력을 탐색할 수 있습니다.
history.pushState(
  { user: 'JohnDoe', loggedIn: true },
  '',
  '/dashboard'
);
  • stateObject: { user: 'JohnDoe', loggedIn: true }는 사용자의 로그인 상태를 저장합니다.
  • url: '/dashboard'는 새로운 URL입니다. 페이지를 새로 고침하지 않고 URL이 /dashboard로 변경됩니다.

history.replaceState(state, title, url)

  • 현재 상태를 교체하며, URL을 변경합니다.
  • 새 이력을 추가하지 않고, 현재 기록을 덮어씁니다.

replaceState() 사용 이유

  • URL을 변경하고 싶지만, 히스토리 스택을 변경하지 않으려는 경우에 유용합니다. 예를 들어, 페이지 상태나 일부 UI를 변경하지만, 사용자가 뒤로 가기 버튼을 눌렀을 때 그 변화를 취소할 수 없게 만들고 싶을 때 사용합니다.
  • 예를 들어, 검색 결과를 필터링하거나 페이지 내에서 동적으로 내용을 변경하는 경우 새 페이지를 추가하지 않고 URL을 변경하려는 경우가 있을 수 있습니다.

window.onpopstate

  • 브라우저에서 뒤로 가기/앞으로 가기 시 발생하는 이벤트입니다.
  • 이 이벤트를 활용하여 특정 상태로 돌아가거나 앞으로 이동할 때의 처리를 할 수 있습니다.
  • popstate는 history.pushState() 또는 history.replaceState()를 사용하여 페이지의 URL을 변경한 뒤, 사용자가 뒤로 가기나 앞으로 가기 버튼을 클릭하여 URL이 변경될 때 발생합니다.
  • popstate 이벤트는 window 객체에서 발생합니다. 이벤트가 발생하면, 이전 상태에 대한 정보는 event.state 객체를 통해 접근할 수 있습니다.
window.addEventListener('popstate', function(event) {
  console.log('popstate 이벤트 발생!');
  console.log('현재 상태:', event.state);
});

SPA 예시

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script></script>
  </head>
  <body>
    <ul>
      <li>
        <a href="/" data-url="home">Home</a>
      </li>
      <li>
        <a href="/about" data-url="about">About</a>
      </li>
      <li>
        <a href="/contact" data-url="contact">Contact</a>
      </li>
    </ul>
    <div id="page">Home 페이지입니다.</div>
  </body>
</html>
// 각 페이지의 콘텐츠 정의
const pages = {
  home: "Home 페이지입니다.",
  about: "About 페이지입니다.",
  contact:
    "Contact 페이지입니다. <input text='text' placeholder='연락처 입력 하세요' />",
};

//링크 클릭 이벤트 처리
const aEls = document.querySelectorAll("a");
aEls.forEach((aEl) =>
  aEl.addEventListener("click", function (e) {
    e.preventDefault();
    const page = e.currentTarget.dataset.url; // 클릭된 링크의 data-url 속성 값을 가져오기
    history.pushState({ page: page }, "", `/${page}`);
  // history.pushState()를 사용하여 새로운 URL과 상태를 히스토리 스택에 추가합니다.

    document.getElementById("page").innerHTML = pages[page];
  //해당 페이지의 콘텐츠를 pages 객체에서 가져와 #page 요소에 표시합니다.
  })
);

//뒤로 가기 및 앞으로 가기 이벤트 처리
//이벤트가 발생하면, event.state에서 이전에 저장한 상태 정보를 가져와서 #page 콘텐츠를 해당 페이지로 업데이트합니다.
window.addEventListener("popstate", function (event) {
  const page = event.state?.page || "home";
  console.dir(event.state?.page || "home"); // event.state?.page가 없으면 기본값인 "home"을 사용합니다.
  console.log("뒤로가기 또는 앞으로 가기가 눌렸음");
  document.getElementById("page").innerHTML = pages[page];
});

0개의 댓글