[JS] Vanilla JS로 SPA 라우터 구현(PJAX 방식)

녕녕·2023년 5월 16일
0

JavaScript🍰

목록 보기
3/6

영화 검색 사이트의 검색페이지와 상세페이지를 SPA로 구현했다. 그 과정에서 알게된 것들을 기록했다.

🌐 Vanilla Javascript로 SPA를 만드는 여러가지 방법

  1. 전통적 링크 방식 : SSR 방식으로 각 페이지마다 고유의 URL이 존재하여 history 관리 및 seo 대응에는 문제가 없음. 다만, 변경사항이 생길 때마다 전체 페이지가 새로고침됨. js는 필요없음
  2. ajax 방식 : 자바스크립트 이용해 비동기적으로 서버와 통신함. 페이지 전체가 아니라 일부만 갱신함. 주소창의 url 변경 안됨(history 관리 안됨). js필요함(seo 대응 안됨)
  3. hash 방식 : url이 동일할 때 hash만 변경되면 서버에 요청 안함. hash는 요청을 위한 것이 아니라, 앵커로 웹페이지 내부서 이동하기 위한 것. js필요함(seo 대응 안됨. 콘텐츠 수집을 위한 크롤러는 js를 실행하지 않기 때문에)
  4. pjax 방식 : pushstate, popstate사용. url을 변경하고 history로 관리하지만 서버로 요청하지 않음.

검색해보니 위의 방법이 있다는 것을 알게 됐고, 이 중 pjax로 SPA를 구현해보았다.

🌐 PJAX

📌 URL 변경 함수

export const handlePushstate = (element, path) => {
  element.addEventListener('click', (e) => {
    e.preventDefault();
    window.history.pushState('', '', path);
    const urlChange = new CustomEvent('urlchange', {
      detail: { href: path },
    });
    document.dispatchEvent(urlChange);
  });
};

요소에 클릭 이벤트리스너를 등록한다. 이벤트리스너 함수 내에 주소창의 URL을 변경하고 URL을 history entry로 추가하지만 서버로 HTTP 요청을 하지는 않는 pushState를 추가한다. URL 주소가 변경되는 것을 알리고 감지할 수 있는 커스텀 이벤트를 만들고, 생성한 커스텀 이벤트를 dispatch() 메서드를 통해 document 객체에 발송한다.

📌 URL 변경되는 요소

<header role="navigation">
	<h1 class="logo">
		<a href="/">Moovie</a>
	</h1>
</header>
const logoEl = document.querySelector('.logo');
handlePushstate(logoEl, '/');

헤더의 로고 클릭시 검색할 수 있는 홈화면으로 이동해야 한다. handlePushstate 함수로 url 을 변경한다.

movieLiEl.innerHTML = `
	<a class='info' href="/detail/${movie.imdbID}" movieId=${movie.imdbID}>
		<p>${movieTitleEl}</p>
        <p>${movieYearEl}</p>
    </a>
`;

const movieIdEl = document.querySelector('.info').getAttribute('movieId');
handlePushstate(movieLiEl, `/detail/?id=${movieIdEl}`);

영화검색결과 하나의 영화 리스트 요소 클릭시, 영화 상세페이지로 이동해야한다. handlePushstate 함수로 url 을 변경한다.

📌 index.js

import search from '/src/pages/Search/index';
import detail from '/src/pages/Detail/index';

search();

const render = async () => {
  let url = window.location.href;
  let path = new URL(url).pathname;
  const searchParams = new URL(url).searchParams;
  const queryString = searchParams.get('id');

  switch (path) {
    case '/':
      search();
      break;
    case '/detail/':
      await detail(queryString);
      break;
    default:
  }
};

document.addEventListener('urlchange', () => {
  render();
});

window.addEventListener('popstate', () => {
  render();
});
  • 기본적으로 search() 함수로 검색페이지를 렌더링한다.
  • URL 변경을 감지하며 urlchange를 수신하여 render() 함수를 실행한다.
  • render() 함수에서는 url 정보를 바탕으로 그에 맞는 페이지를 렌더링한다.
  • 사용자가 뒤로 가기 또는 앞으로 가기 버튼을 클릭할 때 발생하는 popstate 이벤트를 추가하여, 세션기록변경에 따라 페이지가 조건에 맞게 렌더링되도록 한다.

영화검색사이트 프로젝트에서 제일 어려웠던 부분이었다. 그래도 혼자 열심히 찾아보고 고민해낸 끝에, 구현해낸 것이 너무 뿌듯하다! 전체 코드는 깃허브 레포지토리에서 볼 수 있다.

참고

profile
FE Developer | 차근차근

0개의 댓글