History API 로 SPA 구현

이윤표·2024년 6월 28일
0

자바스크립트로 URL 라우팅을 구현하려고 한다. 바닐라 자바스크립트를 사용중이고 클라이언트 단 라우팅을 지원하는 라이브러리를 사용할 수 없기 때문에 자바스크립트의 Histroy API 를 사용하였다.

요구사항

로그인 버튼이나 회원가입 버튼, 홈 버튼 등을 클릭할 때 URL를 변경시키고 동시에 UI도 변경시킨다.

JS로 클라이언트 단에서 라우팅 처리

이 navigate() 함수는 상태 객체를 인자로 받고, 상태 객체 안에 담겨있는 url 속성을 읽어서 url 에 맞는 UI를 화면에 보여준다. 따라서 이 함수를 호출하면 HTML에서 페이지의 내용이 바뀐다.

/**
 * 주어진 상태에 따라 해당 URL에 맞는 뷰를 표시.
 * @param {Object} state - 상태 객체.
 */
function navigate(state) {
  const { url } = state;
  const views = {
    chatting: document.querySelector("#chattingView"),
    login: document.querySelector("#loginView"),
  };

  switch (url) {
    case ROUTES.HOME:
      updateView(views, views.chatting);
      break;
    case ROUTES.LOGIN:
      updateView(views, views.login);
      break;
    default:
      break;
  }
}

/**
 * 업데이트할 뷰를 표시하고 다른 뷰를 숨긴다.
 * @param {Object} views - 모든 뷰를 담고 있는 객체.
 * @param {HTMLElement} viewToShow - 표시할 뷰의 DOM 요소.
 */
function updateView(views, viewToShow) {
  Object.values(views).forEach((view) => view.classList.add("hidden"));
  viewToShow.classList.remove("hidden");
}

updateRoute 핸들러 생성

이제 헤더 버튼에 클릭 이벤트 핸들러를 설정한다.

사용자가 각 버튼을 클릭하면 브라우저의 주소 표시줄의 URL이 바뀔 수 있도록 history.pushState() 메서드를 호출한다. 첫 번째 인자에는 경로 정보가 담겨있는 상태 객체를 넘기고, 세 번째 인자로는 브라우저의 주소 표시줄에 표시할 경로를 문자열로 넘김니다. 마지막으로 위에서 작성한 navigate() 함수에 동일한 상태 객체를 넘겨서 페이지 내용이 바뀌게한다.

/**
 * 주어진 URL로 브라우저의 히스토리 상태를 업데이트 및 해당 상태로 navigate.
 * @param {string} url - 새로 업데이트할 대상 URL
 */
export function updateRoute(url) {
  const state = { url };
  if (url === window.location.pathname) {
    history.replaceState(state, "", url);
  } else {
    history.pushState(state, "", url);
  }
  navigate(state);
}

// 핸들러 등록
$headerTitle.addEventListener("click", () => updateRoute(ROUTES.HOME));

이 때, 동일한 버튼을 연속적으로 클릭하면 동일한 history가 history stack 에 쌓이기 때문에 이를 방지하기 위해 replaceState() 메서드를 사용한다.

PopStateEvent 이벤트 핸들러 등록

여기까지만 하면 URL 변경에 따라 UI가 적절하게 변경된다. 하지만 ‘뒤로가기’ 또는 ‘앞으로 가기’를 클릭하면 주소표시창에 URL만 변경될 뿐 페이지의 UI는 그대로다.

이 문제를 해결하기 위해 윈도우에서 발생하는 popstate 이벤트를 감지해서 라우팅 처리해준다. 위에서 pushState() 와 replaceState() 메서드의 첫 번째 인자로 상태 객체를 넘겨주었기 때문에, 해당 페이지로 뒤로 가기나 앞으로 가기가 되면, 이벤트 핸들러에 매개 변수로 해당 상태 객체가 넘어오게 된다. 따라서 이 상태 객체를 그대로 navigate() 함수에 인자로 넘겨준다.

/**
 * popstate 이벤트가 발생할 때 호출되어, 이벤트 상태를 가지고 navigate 한다.
 * @param {PopStateEvent} event - popstate 이벤트 객체.
 */
function popStateHandler(event) {
  const { state } = event;
  navigate(state);
}

window.addEventListener("popstate", popStateHandler);

데모

histroy API 데모

해당 코드 깃허브 주소 https://github.com/lee-yun-pyo/Login-Practice

profile
프론트엔드 개발자 지망생

0개의 댓글