클라이언트 사이드 렌더링을 하는 SPA(Single Page Application)의 특징을 가지는 React에서 다른 URL마다 다른 컴포넌트 뷰를 보여주려면 React-Router 라이브러리가 필요하다. 또한 클릭이벤트가 발생할 때 페이지를 새로고침 없이 이동하기 위해 history를 활용할 수 있다.
브라우저가 관리하는 세션 히스토리(session history), 페이지 방문 이력을 제어하기 위한 웹 표준 API. 웹 애플리케이션이 브라우저의 세션 기록 스택을 조작하고 탐색 기록을 관리할 수 있게 해준다. 여기서 세션은 브라우저마다 살짝 다를 수 있지만 보통 사용자가 새 창이나 탭을 열 때 생성되고 해당 창이나 탭을 닫을 때 소멸한다. 이를 통해 페이지 리로드 없이 URL을 변경하고, 사용자가 브라우저의 뒤로 가기 및 앞으로 가기 버튼을 사용할 수 있게 한다.
자바스크립트에서 History API는 기본적으로 history 전역 객체를 통해서 사용해 볼 수 있으며 window나 document 전역 객체를 통해서도 접근할 수 있다.
history.length; // 1
window.history.length; // 1
document.history.length; // 1
현재 세션에서 얼마나 많은 페이지를 방문했는지는 History API에서 제공하는 length 프로퍼티에 접근하면 된다. history.back(), history.forward(), history.go() 메서드는 SPA에서 잘 사용되지 않는다. 메서드를 호출하면 브라우저는 해당 페이지를 reload하게 되지만, SPA에서는 일반적으로 URL이 바뀌더라도 전체 페이지를 다시 로딩하지 않기 때문이다.
브라우저의 현재 URL 조작할 수 있는 pushState()와 replaceState() 메서드는 브라우저 주소 표시줄의 URL만 갱신되고 실제로 해당 페이지가 다시 불러오지는 않는다. 이러한 특징 때문에 자바스크립트로 해당 URL에 맞게 페이지를 부분 업데이트할 수 있다.
세션 기록 스택에 새로운 상태를 추가합니다.
현재 세션 기록의 상태를 새로운 상태로 대체합니다.
사용자가 브라우저에서 뒤로 가기나 앞으로 가기를 하면 back()이나 forward() 메서드를 호출한 것처럼 브라우저가 페이지를 다시 불러오게 된다. 이렇게 될 경우 SPA에서 문제가 발생할 수 있다. “뒤로 가기”나 “앞으로 가기” 버튼은 통제할 수 있는 페이지 상 밖에 위치하여 클릭 이벤트를 감지할 수는 없다. 이를 해결해주는 방법이 PopStateEvent이다. 사용자가 브라우저에서 뒤로 가기나 앞으로 가기를 할 때 window 전역 객체에서 발생한다. 그러므로 자바스크립트로 이벤트 핸들러를 걸어서, 해당 URL에 부합하는 내용을 클라이언트에서 렌더링할 수 있다.
window.addEventListener("popstate", (event) => {
// 이벤트에 들어 있는 상태 객체를 읽어서 클라이언트 단 라우팅 처리
});
React Router의 History는 브라우저의 History API를 기반으로 하여 SPA 내에서 라우팅을 관리하는데 더 높은 수준의 추상화를 제공한다. React Router는 자체적으로 History 객체를 사용하여 브라우저의 탐색을 관리하며, 이 History 객체는 브라우저의 History API를 내부적으로 사용한다.
push(path, state): 새로운 경로로 이동하고 새로운 항목을 세션 기록 스택에 추가
replace(path, state): 현재 항목을 새로운 경로로 대체
go(n): 현재 위치에서 n만큼 이동
goBack(): 이전 페이지로 이동
goForward(): 다음 페이지로 이동
React Router에서 경로를 변경할 때는 push 메서드가 사용된다. 새로운 경로가 현재 경로를 대체하면서 이전 페이지를 브라우저 히스토리 스택에 추가하게 된다. 즉, 사용자가 뒤로가기를 누르면 이전 페이지로 이동할 수 있다.
replace는 보통 이전 페이지에 접근하는 것이 어색한 상황에 사용된다. 주로 사용되는 예로는 로그인 완료 후 뒤로가기를 눌렀을 때 로그인 페이지로 다시 접근이 가능한 것은 어색한 상황이다. 이를 방지하기 위해 replace를 사용해 새로운 경로로 대체해줄 수 있다.
실제 프로젝트에서는 다음과 같은 이슈가 있었다.
React Router를 이용하여 비회원 접근 제어를 진행해주었다. 이때, 회원만 접근 가능한 페이지를 비회원이 접근했을 때 로그인 페이지로 강제 이동을 시켜주게 되었는데, 이 경우 뒤로가기 버튼이 작동을 하지 않았다.
그 이유는 History stack에 메인페이지 -> 회원 접근 페이지 -> 로그인이 추가되어 뒤로가기를 눌러도 다시 회원 접근 페이지로 이동하기 때문에 로그인 페이지로 다시 돌아오지만, 사용자에게는 변함이 없는 것으로 보이게 된다. 이를 해결해주기 위해 로그인으로 이동시킬 때 Navigate에 replace 속성을 추가해주어 해결하게 되었다.

History는 사실 Router를 구현하면서 굳이 신경쓰지 않았던 부분이었다. Router를 사용하는 이유는 단순히 라우팅을 구현하기 위함이라고 생각했고, 페이지 이동 잘 되면 그만~ 이라고 생각했는데 사용자 테스트에서 해당 오류를 발견해준 사람이 있어서 이 부분에 대한 오류 해결 방법을 찾아보다가 History에 대해 알게 되었다. 당시에는 아~ 이런 게 있구나 하고 넘어갔지만, 자세하게 알고싶어서 프로젝트 후 찾아보게 되었다. 프론트엔드는 참 할 게 정말 많다는 걸 느꼈다. 사용자 경험도 생각해야 하고, 기능도 잘 굴러가야 하고.. 그 와중에 신경 써줘야 할 건 정말 한 두가지가 아니다. 뒤로가기 버튼까지 신경써줘야 한다는 것에 정말... 프론트엔드는 다재다능해야 하구나를 배운 것 같다. 나름 그런 구현들이 재미있지만, 아직도 내가 모르는 것들도 구현해야 하는 게 정말 많겠지???????? 프론트엔드 공부는 진짜... 힘들다는 걸 또 한 번 배우고 간다.
Project_Cheerleader — (2) React Route dom history를 사용한 페이지 이동
자바스크립트의 History API와 클라이언트 단 라우팅