Typescript + React + React Testing Library + Jest 환경 구성 및 몇가지 간단한 테스트 코드 예시
브라우저의 이해 #2 히스토리 그리고 history API
2019-03-14
Explanation
이제는 비동기 통신이나 SPA(싱글 페이지 애플리케이션)은 전혀 새롭지 않은 기술?이 된 거 같아요. 저 역시도 대부분 Angular나 React같은 프레임웍을 사용해서 웹 애플리케이션을 개발하고 있는데요. 어쩌면 너무 당연스럽게 프레임웍을 사용해서 개발하다보니(너무 편하게 프레임웍이 제공해주다 보니) 오히려 기본적인 브라우저의 히스토리 처리에 대해서 잘 알지 못하고 있었더라고요. 그래서 오늘은 브라우저의 히스토리 기능?(History API라고 해야 할까요?)에 대하여 알아보려 합니다.
여기서 말하는 브라우저의 히스토리는 우리가 브라우저를 켜고 이곳 저곳 웹페이를 돌아다닌 기록을 이야기해요. 간단하게 브라우저에서 뒤로가기를 눌렀을때, 브라우저는 이전 웹 페이지를 기억하고 있다가 보여주죠. 이때 우리는 이전보다 훨씬 빠른 속도로 페이지가 로드되는 것을 확인할 수 있어요. 아마도 브라우저가 각각의 이동 했던 웹 페이지의 데이터를 기억하고 있다가 빠르게 보여주는 것이겠지요??
그럼 본격적으로,
DOM의 window 객체는 history 객체를 통해서 브라우저의 히스토리에 접근할 수 있는데요. 우선은 아주 간단하게 back(), forward(), go() 메서드를 이용해서 브라우저의 앞으로가기 뒤로가기 기능을 구현할 수 있답니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 뒤로가기 window.histroy.back(); // 앞으로가기 window.histroy.forward(); // 특정 위치로 가기 window.history.go(-1); // window.history.back()과 동일하기 한 페이지 뒤로 이동합니다. window.history.go(1); // window.history.forward()와 동일하게 한 페이지 앞으로 이동합니다. window.history.go(-2); // 두 페이지 이전으로 이동합니다. |
위와 같이 브라우저의 히스토리 기록을 이동할 수 있어요. 그리고 length 속성을 이용하여 히스토리가 몇 페이지로 되어 있는지 확인 할 수 있습니다.
1 2 |
console.log(window.history.length); // 현재 페이지를 기준으로 앞, 뒤 페이지가 없다면 1이 출력됩니다. |
적고 보니 MDN과 똑같네요…
참고. https://developer.mozilla.org/ko/docs/Web/API/History_API
HTML5는 히스토리 엔트리를 추가하거나 변경하기 위해 pushState()와 replaceState()라는 메서드를 제공하고 window.onpopstate 이벤트와 연동하여 동작합니다. 그리고 pushState와 replaceState의 차이점은 pushState는 히스토리 엔트리에 새로운 엔트리를 추가하는 메서드이고 replaceState는 현재의 히스토리 엔트리를 변경한답니다.
history.pushState(), history.replaceState() 두개의 메서드 모두 3개의 파라미터(매개변수)를 가지고 호출할 수 있답니다.
1 2 |
history.pushState({data: 'pushState1'}, '', '/pushState1'); history.replaceState({data: 'replaceState'}, '', '/replace-state'); |
여기에서 첫번째 파라미터는 history.state에 기록할 데이터이고, 두번째 파라미터는 타이틀 값인데 아직 사용이 정확하게 정의, 구현 되어있지 않은거 같아요. 그래서 그냥 빈 문자열을 넣었습니다. 그리고 세번째 인자는 새로운 히스토리 엔트리의 URL 값입니다.
저는 세번째 파라미터로 절대 경로 ‘/abc’ 로 지정했는데요. 여기서 설정하는 URL은 기존의 URL을 기준으로 동작하기 때문에 상대 경로로 설정 할 수도 있어요.(ex: ‘./abc’)
그리고 여기서 첫번째 파라미터로 입력한 데이터값은 history.state에 객체 사본으로 사용됩니다.
아래의 간단한 예제를 확인하면 이해하는데 조금 더 이해하기 좋을 거 같아요.
간단한 예제 코드를 깃헙에서 다운로드(클론)해서 직접 확인할 수 있습니다.
https://github.com/falsy/blog-post-example/tree/master/history-api-sample
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<!doctype html> <html lang="ko"> <head> <title>History API Sample</title> <meta charset="utf-8"> <style> section {margin: 20px 0;} </style> </head> <body> <section> <h2>push state</h2> <button id="push-state1">pushState1</button> <button id="push-state2">pushState2</button> <button id="push-state3">pushState3</button> </section> <section> <h2>replace state</h2> <button id="replace-state">replaceState</button> </section> <section> <h2>history state</h2> <span id="state"></span> </section> </body> </html> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// 현재의 history state 값을 출력합니다. const currentHistoryState = () => { document.getElementById('state').innerText = JSON.stringify(history.state); }; currentHistoryState(); // pushState() document.getElementById('push-state1').addEventListener('click', () => { history.pushState({data: 'pushState1'}, '', '/push-state1'); currentHistoryState(); }); document.getElementById('push-state2').addEventListener('click', () => { history.pushState({data: 'pushState2'}, '', '/push-state2'); currentHistoryState(); }); document.getElementById('push-state3').addEventListener('click', () => { history.pushState({data: 'pushState3'}, '', '/push-state3'); currentHistoryState(); }); // replaceState() document.getElementById('replace-state').addEventListener('click', () => { history.replaceState({data: 'replaceState'}, '', '/replace-state'); currentHistoryState(); }); // 브라우저의 뒤로가기 / 앞으로가기를 누르면 history state 값을 확인하여 출력합니다. window.addEventListener('popstate', () => { currentHistoryState(); }); |
간단하게 글로 이야기를 하면, push state 버튼들을 누르면 화면을 새로 그리지 않고 URL이 파라미터로 보낸 URL 값으로 변경되고 히스토리 엔트리에 추가됩니다. 그래서 뒤로가기나 앞으로가기를 누르면 이전의 URL로 다시 화면을 새로 그리지 않고 이동할 수 있답니다.
그리고 replace state 버튼은 새로운 엔트리를 추가하지 않고 현재의 엔트리 값을 변경하기 때문에 뒤로가기로 이전 URL로 이동할 수 없답니다. 예를 들자면,
1. pushState()
pushState1 클릭 -> URL이 /push-state1 로 변경 -> pushState2 클릭 -> URL이 /push-state2 로 변경 -> 브라우저의 뒤로가기 누르면 -> URL이 /push-state1 로 변경
2. replaceState()
pushState1 클릭 -> URL이 /push-state1 로 변경 -> pushState2 클릭 -> URL이 /push-state2 로 변경 -> replace-state 클릭 -> URL이 /replace-state 로 변경 -> 브라우저의 뒤로가기 누르면 -> URL이 /push-state1 로 변경
참고링크.
1. https://developer.mozilla.org/ko/docs/Web/API/History_API
2. https://www.zerocho.com/category/HTML&DOM/post/599d2fb635814200189fe1a7
끝