두번째 팀프로젝트가 어느새 지나가고, 본격적인 리액트 학습 주차에 접어들었습니다.
SPA의 원리와 장단점에 대해 공부하다가, Hash Routing 이라는 방법으로
바닐라 자바스크립트에서 SPA 처럼 구현할 수 있다는 것을 알게 되었습니다.
리액트는 History API 로 이러한 SPA 를 구현하는 것으로 알고 있는데,
Hash Routing 은 처음 보아서, 두 가지 방법을 모두 정리해 보아야겠다고 생각했습니다.
Hash Routing
해시드 라우팅은 URL의 해시를 사용하여 클라이언트 측에서 페이지의 구역을 로드합니다.
URL의 #
부분은 서버로 전송되지 않기 때문에, 이를 활용하여 페이지 리로드 없이 URL을 변경할 수 있습니다.
예를 들어, http://example.com/#/page1
에서 #/page1
은 브라우저가 해석하고 서버에는 영향을 주지 않습니다.
이 방법은 자바스크립트로 window.location.hash
를 체크하고, 해시가 변경될 때마다 필요한 뷰나 데이터를 로드하는 방법입니다.
// 페이지 생성 클래스
class Page {
constructor() {
this.htmlString = "";
}
render() {
document.getElementById("root").innerHTML = this.htmlString;
}
}
import About from "./pages/About.js";
import Home from "./pages/Home.js";
import NotFound from "./pages/NotFound.js";
const routes = {
"#/": new Home(),
"#/about": new About(),
404: new NotFound(),
};
// router.js
export const renderPage = () => {
const path = window.location.hash || "#/";
const selectedPage = routes[path] ?? routes[404];
selectedPage.render();
};
// main.js
import { renderPage } from "./router.js";
renderPage();
// hashchange 라는 이벤트가 있다고 합니다. 결국 요걸로 하는 거였네요.
window.addEventListener("hashchange", renderPage);
History API?
React Router와 같은 최신 프레임워크에서는 대체로 히스토리 API를 사용합니다.
이 API는 HTML5에 도입된 기능으로, 브라우저의 히스토리를 조작할 수 있게 해 주며,
해시를 사용하지 않고도 URL 경로를 직접 변경할 수 있습니다.
history.pushState()
나 history.replaceState()
함수를 사용하여 브라우저의 히스토리 스택에 상태를 추가하거나 변경할 수 있고,
이렇게 하면 페이지를 새로고침하지 않고 URL을 업데이트할 수 있습니다.
예를 들어, React Router에서는 이러한 메소드들을 사용하여 SPA 내에서 사용자의 라우팅을 처리하고,
브라우저의 뒤로 가기나 앞으로 가기 등의 행동에 자연스럽게 대응할 수 있습니다.
History API 를 사용하는 이유
React Router에서 #/
과 같은 해시를 사용하지 않는 이유는,
히스토리 API를 통해 더 자연스러운 URL 경로를 제공하고,
이 경로들이 서버와의 통신에도 사용될 수 있기 때문입니다.
이는 애플리케이션이 좀 더 전통적인 멀티페이지 웹사이트처럼 느껴지게 할 수 있어,
사용자 경험과 검색 엔진 최적화(SEO)에 도움이 됩니다.
History API는 브라우저에서 JavaScript를 이용하여 사용자의 세션 히스토리를 조작할 수 있는 수단을 제공합니다.
이 API를 사용하면 SPA에서 페이지를 전환할 때 페이지를 새로 고침하지 않고도 URL을 변경할 수 있습니다.
이는 사용자에게 전통적인 웹사이트처럼 느껴지게 하는 동시에 싱글 페이지 애플리케이션의 장점을 유지할 수 있게 해줍니다.
History API 사용법
- pushState(state, title, url): 이 메소드는 브라우저의 히스토리 스택에 새로운 상태를 추가합니다. 이때 페이지는 새로고침되지 않지만, 주소 표시줄의 URL은 바뀝니다.
state
: 새로운 히스토리 항목에 연결할 데이터 객체입니다. 이 상태는 나중에popstate
이벤트가 발생할 때event.state
로 접근할 수 있습니다.title
: 대부분의 브라우저는 현재 이 파라미터를 무시합니다. 일부 브라우저는 추후 사용을 위해 비워둘 수 있습니다.url
: 새로운 히스토리 엔트리의 URL입니다. 같은 출처(origin) 내의 URL이어야 합니다.
- replaceState(state, title, url): 현재의 히스토리 엔트리를 새로운 것으로 대체합니다.
pushState
와 달리, 히스토리 스택에 새로운 엔트리를 추가하지 않고 현재 엔트리를 수정합니다. - back(), forward(), go(n): 이 메소드들은 각각 브라우저 히스토리에서 뒤로, 앞으로, 또는 지정된 히스토리 엔트리로 이동합니다.
// 현재 URL이 `http://example.com` 일 때
// 새로운 히스토리 엔트리를 추가
history.pushState({page: 1}, "Title 1", "page1.html");
// 현재 히스토리 엔트리를 대체
history.replaceState({page: 2}, "Title 2", "page2.html");
// 히스토리에서 뒤로 이동
history.back(); // URL이 `http://example.com`로 돌아갑니다.
// 히스토리에서 앞으로 이동
history.forward(); // URL이 다시 `http://example.com/page2.html`이 됩니다.
popstate
이벤트
popstate
이벤트는 히스토리 엔트리가 변할 때마다 발생합니다. 예를 들어 사용자가 뒤로 가기를 누를 때 이벤트가 트리거되며, 이 때 이벤트 객체의 state
속성을 통해 pushState
또는 replaceState
메소드에서 설정한 상태 객체에 접근할 수 있습니다.
window.addEventListener("popstate", function(event) {
console.log("popstate fired!");
// 여기에 { page: 1 } 같은 객체들이 있음
console.log(event.state);
});
그렇다고 합니다. 비교해서 살펴보니, History API는 페이지 로드 없이 동적으로 사용자의 히스토리와 상호작용하는 효과적인 수단이고 React Router 같은 라이브러리에서 이를 활용하여 더욱 쉽게 라우팅을 구현한다고 볼 수 있을 것 같습니다.
pushState vs replaceState
pushState
pushState
메소드는 히스토리 스택에 새로운 엔트리를 추가합니다.
이는 사용자가 어떤 작업을 통해 새로운 상태로 이동했을 때, 그 이전 상태를 유지하면서 새로운 상태를 스택에 추가할 때 사용됩니다.
즉, pushState
는 사용자가 "앞으로" 이동했을 때 이전 상태로 "뒤로" 갈 수 있게 해줍니다.
(브라우저 뒤로가기 앞으로가기 가능)
예시:
사용자가 게시물 목록에서 특정 게시물을 클릭하여 상세 페이지로 이동하는 경우, pushState
를 사용하여 URL을 해당 게시물의 URL로 변경할 수 있습니다. 사용자가 브라우저의 "뒤로" 버튼을 클릭하면, 목록 페이지로 돌아갈 수 있습니다.
// 목록 페이지에서
history.pushState({page: 'post'}, "Post Title", "post.html");
replaceState
replaceState
메소드는 현재 히스토리 엔트리를 새로운 것으로 대체합니다.
즉, 현재 위치를 수정하되, 새로운 히스토리 엔트리를 스택에 추가하지 않습니다.
이는 사용자가 특정 상태로 이동했으나, 그 이전 상태로 돌아갈 필요가 없는 경우에 사용됩니다.
예시:
사용자가 양식을 통해 설정을 변경하는 페이지에서 변경 사항을 저장한 후
URL을 변경하고자 할 때 replaceState
를 사용할 수 있습니다.
이 경우, 변경 사항이 저장된 상태에서 URL만 변경하고, "뒤로" 버튼을 눌렀을 때 설정 변경 전의 폼 상태로
돌아가는 것을 방지할 수 있습니다. (로그인 후에 뒤로가기 막아야 한다거나)
// 설정 변경 후
history.replaceState({page: 'settings'}, "Settings", "settings.html");
'javascript' 카테고리의 다른 글
[240527 TIL] 날짜 유효성 검사 (0) | 2024.05.27 |
---|---|
[240513 TIL] 불변성 원칙과 순수 함수 (0) | 2024.05.13 |
[240510 TIL] 이벤트 버블링, 캡처링, 관련메소드 (0) | 2024.05.10 |
[240508 TIL] Object.assign, 깊은 복사 (1) | 2024.05.08 |
[240507 TIL] Object.is (0) | 2024.05.07 |