VanilaJS로 SPA 구현하기😎 - 1

기록일기📫·2021년 2월 10일
32

최근에 J2KB 2기에 진행되는 해커톤으로 동아리 소개 웹페이지를 만드는 프로젝트를 진행중에 있다! javascript도 연습 할 겸 Vanila JS만 이용해서 프로젝트를 진행 중이다.

사실 크게 어려움을 겪을거라고 생각을 안하고 팀원들에게 '제가 포맷 만들고 커밋 하겠습니다!' 했는데, 예상과는 달리 처음부터 생각보다 많은 것을 수동으로 구현해야 했다...😐

공부 한 내용도 정리 할겸 포스팅을 해보려 한다.😊

✨ 전체 코드는 여기서 확인해 보실 수 있습니다 ✨

요구사항👀

Vanila JS로 SPA를 구현하기 위해 처음에 해결해야 하는 상황은 두가지였다.

  1. 필요한 곳만 부분적으로 렌더링을 할 것(페이지 하나로 구현)
  2. 적절한 라우팅 처리를 해줄 것(앞으로가기, 뒤로가기가 가능하게 할것)

Vanila JS만을 이용해서 구현하기로 했기 때문에, 프레임워크의 도움 없이 변경이 필요한 부분만 바꿔서 렌더링을 해줄 수 있어야 했다. 두번째로는 브라우저에 주소를 바꿔주는 routing 문제를 해결해야 했다.

진행해보다가 생각보다 어려워서 멘붕이 왔었는데(때려 칠까 잠시 고민했다😂😂),

결론적으로는 처음 문제는 렌더링이 되어야 하는 상황이 발생하면 html을 동적으로 교체해 줌으로써 해결했고,

두번째 문제는 Window History API를 이용해서 해결하였다!

Window History API? 🤔

방법에 대해 본격적으로 알아보기 전에, Window History API에 대해 간단히 살펴보자.

SPA로 어플리케이션을 제작 했을때의 단점은 하나의 싱글 페이지로 구현 되다 보니 브라우저의 앞으로가기, 뒤로가기를 사용할 수 없다는 것이다.

그래서 vue, react 같은 SPA 프레임워크를 사용할 때 우리는 vue-route, react-router 라이브러리를 같이 사용하여 적절한 routing 처리를 해준다. 하지만 vanila JS에는 그런 라이브러리가 없으므로, routing을 직접 구현해 주어야 한다.🙄

그래서 어떻게 하는데?

브라우저는 주소 내역을 목록으로 관리한다. 브라우저는 뒤로가기, 앞으로가기 요청이 올때마다 가지고 있는 주소 목록을 참고하여 이동한다(url을 변경한다).

우리는 window history API의 pushstate와 window 객체의 onpopstate를 직접 이용해서 브라우저의 주소를 바꿔 줄 것이다. (나중에 알게 된 사실이지만 react-router도 내부적으로는 이렇게 구현되어 있었다!)

pushstate

history.pushState 메서드를 이용하면 우리가 직접 주소 목록에 새로운 주소를 추가할 수 있다. 즉 임의로 새 주소로 브라우저의 주소를 바꿔버릴 수 있는 것이다!

popstate

window.onpopstate는 client가 앞으로가기, 뒤로가기를 했을때 발생하는 이벤트이다.
그래서 window.onpopstate를 이용하면 사용자가 뒤로가기나 앞으로 가기를 했을때, 어떤 행동을 하게 할건지를 정의할 수 있다.

그래서 이렇게 합니다!

따라서 우리는 위의 두가지 메서드를 사용하여 SPA를 구현해볼 것이다. history.pushState를 이용해서 새로운 주소로 routing 처리를 해주고, window.onpopstate를 이용해서 client가 앞으로가기나 뒤로가기를 눌렀을때 적절한 화면으로 바꿔주어 SPA를 구현해 볼 것이다.

설명이 좀 길었는데, 그러면 이제 코드를 통해 직접 만들어 보자.😁😁😁

구현

우리가 만드려는 방식은 기존 react app과의 방식과 상당히 비슷하다. CRA로 react App을 생성하면 아래와 같이 /public 경로에 index.html 파일이 생성된다.

여기서 component들을 렌더링할 때, root태그에 우리가 동적으로 생성한 html이 삽입 되게 된다.
실제 웹에서 확인해 보면 다음과 같다. (예시입니다!)

react가 root 밑에 app, navbar 같은 html element를 동적으로 추가해준 것이다!

그러면 javascript를 이용해서 SPA를 구현해보자. 일단 index.html 파일을 생성한다.

navigation bar에서 클릭 되는 부분에 따라 적절한 라우팅 처리를 해주고, <div id="app-content"></div> 부분을 우리가 원하는 html element들로 채워 넣을 것이다!

우선 navigation bar가 클릭 될 때 마다 화면이 갱신되게 하기 위해 navigation에 li 태그를 모아서 클릭 이벤트를 달아준다.

+++2021/03/10 추가)
💡 부모 element인 nav 태그에 click event를 달고 이벤트 위임을 통해 진행하면 조금 더 효율적인 코드를 작성할 수 있습니다.😊😊

클릭 시 콜백 함수가 하는 역할은 click된 li 태그의 route attribute를 가져온 후, historyRouterPush 함수를 호출하는 것이다.

그러면 실제로 클릭 됐을 때 historyRouterPush 함수에서는 어떤 일이 일어날까? 우선 historyRouterPush가 처음으로 하는 일은 pushState를 이용하여 브라우저의 주소를 바꾸는 일이다.

window.history.pushState({}, pathName, window.location.origin + pathName) 에서 첫 번째 인자는 바뀐 주소와 함께 저장할 데이터 객체이고, 두 번째 인자는 바꿀 제목, 세 번째 인자는 바꿀 주소이다.

첫번째 인자의 경우 지금은 저장해야할 데이터가 없기 때문에 빈 객체를 전달하였다.

pushState를 통해 pathName으로 현재 브라우저의 주소를 바꿔준 후에 renderHTML 함수를 호출하여 app-content 내부의 innerHTML을 바꿔주면 새로운 페이지를 보여줄 수 있다.😊

이제 브라우저의 주소와 화면을 바꿔주는 과정까지 진행 하였으니, client가 앞으로가기나 뒤로가기를 눌렀을때 페이지를 렌더링하는 과정을 처리 해 주어야 한다.

지금 상태로는 앞으로가기와 뒤로가기를 누르면 url은 바뀌지만, pushState를 통해 임의로 url만 바꿔준 것이기 때문에 실제 화면은 바뀌지 않는다.

앞서 onpopstate는 실제로 client가 앞으로가기나 뒤로가기를 했을때 호출된다고 했다. 따라서 우리는 window.onpopstate 이벤트를 이용해 화면을 바꿔줄 수 있다!

브라우저의 주소를 담고있는 location 객체를 이용하여 window.location.pathname으로 바뀐 브라우저의 주소를 받아 renderHtml 함수를 호출해서 적절하게 화면을 바꿔준다.

이렇게 드디어! 바닐라 자바스크립트로 동작하는 SPA를 완성했다!😎

후기

SPA를 만들어 보는 과정에서 window의 History API부터 웹팩 설정까지 여러가지를 공부할 수 있었다. 프레임워크만 사용할때는 고민하지 않았던 많은 부분을 고민해보며, 자바스크립트에 대한 이해도가 높아진것 같아 뿌듯하다.😊

참고 문서

모르는 부분이 많아서 많은 분들의 코드와 포스팅을 참조했다. 함께 보면 이해에 도움이 될 것 같다.

https://poiemaweb.com/js-spa
https://www.youtube.com/watch?v=6BozpmSjk-Y&feature=youtu.be
https://kdydesign.github.io/2020/10/06/spa-route-tutorial/
https://www.zerocho.com/category/HTML&DOM/post/599d2fb635814200189fe1a7

3개의 댓글

comment-user-thumbnail
2021년 2월 14일

감사합니다!! 많은 도움되었습니다. (좋아요 1)

1개의 답글
comment-user-thumbnail
2022년 11월 24일

안녕하세요.
onload함수의 contentDiv가
const contentDiv =document.querySelector("#app-content") 의미인가요?

답글 달기