애플리케이션을 구현하다보면 특정 상황에서 뒤로 가기를 했을 때 예상되는 페이지가 있거나 의도하는 페이지로 이동을 시도하는 상황이 생길 수 있습니다.
History API나 URL 변경 방식을 제대로 알지 못하면 뒤로 가기를 했을 때 엉뚱한 곳으로 가는 상황이 생기거나, 특정 URL로 변경하려면 어떻게 해야 하는지 모르기 때문에 이에 대한 학습이 필요해 한 번 정리해봤습니다.
JavaScript의 History API는 웹 브라우저의 세션 기록(history)을 조작할 수 있는 강력한 도구입니다. 이를 통해 개발자는 사용자가 방문한 페이지의 URL을 변경하거나, 뒤로 가기/앞으로 가기 기능을 제어할 수 있습니다. History API는 주로 단일 페이지 애플리케이션(SPA)에서 사용됩니다.
history.length
현재 브라우저 세션의 기록 목록에 있는 항목의 수를 반환합니다.
console.log(history.length); // 예: 5
history.state
현재 기록 항목과 관련된 상태 객체를 반환합니다.
console.log(history.state);
history.back()
세션 기록에서 이전 페이지로 이동합니다.
history.back();
history.forward()
세션 기록에서 다음 페이지로 이동합니다.
history.forward();
history.go(n)
세션 기록에서 특정 위치로 이동합니다. n이 0이면 현재 페이지를 다시 로드하고, 양수이면 앞으로, 음수이면 뒤로 이동합니다.
history.go(n);
history.pushState(state, title, url)
세션 기록 스택에 상태를 추가합니다. URL을 변경하지만 페이지를 새로 고침하지 않습니다.
history.pushState({ page: 1 }, "title 1", "/page1");
history.replaceState(state, title, url)
현재 기록 항목을 주어진 상태와 URL로 바꿉니다.
history.replaceState({ page: 2 }, "title 2", "/page2");
window.onpopstate 이벤트
브라우저의 뒤로 가기 또는 앞으로 가기 버튼을 누르거나, history.back(), history.forward(), history.go() 메서드를 호출할 때 발생합니다. 이 이벤트를 통해 상태를 복원할 수 있습니다.
window.onpopstate = function (event) {
console.log(
"location: " + document.location + ", state: " + JSON.stringify(event.state)
);
// 상태 복원 로직
};
window.addEventListener("popstate", (event) => {
alert(
`location: ${document.location}, state: ${JSON.stringify(event.state)}`
);
});
history.pushState({ page: 1 }, "title 1", "?page=1");
history.pushState({ page: 2 }, "title 2", "?page=2");
history.replaceState({ page: 3 }, "title 3", "?page=3");
history.back(); // "location: http://example.com/example.html?page=1, state: {"page":1}"라는 알림이 발생합니다.
history.back(); // "location: http://example.com/example.html, state: null"라는 알림이 발생합니다.
history.go(2); // "location: http://example.com/example.html?page=3, state: {"page":3}"라는 알림이 발생합니다.
세션 기록 동작 단계별 자세한 설명
history.pushState({ page: 1 }, "title 1", "?page=1");
• 현재 페이지 URL은 http://example.com/example.html입니다.
• pushState는 현재 URL을 http://example.com/example.html?page=1로 변경하고, 상태 { page: 1 }를 기록에 추가합니다.
• 세션 기록 스택: [null, { page: 1 }]
• 현재 페이지: http://example.com/example.html?page=1history.pushState({ page: 2 }, "title 2", "?page=2");
• 현재 페이지 URL은 http://example.com/example.html?page=1입니다.
• pushState는 현재 URL을 http://example.com/example.html?page=2로 변경하고, 상태 { page: 2 }를 기록에 추가합니다.
• 세션 기록 스택: [null, { page: 1 }, { page: 2 }]
• 현재 페이지: http://example.com/example.html?page=2history.replaceState({ page: 3 }, "title 3", "?page=3");
• 현재 페이지 URL은 http://example.com/example.html?page=2입니다.
• replaceState는 현재 URL을 http://example.com/example.html?page=3로 변경하고, 상태 { page: 3 }로 기존 상태를 대체합니다.
• 세션 기록 스택: [null, { page: 1 }, { page: 3 }]
• 현재 페이지: http://example.com/example.html?page=3history.back();
• 현재 페이지 URL은 http://example.com/example.html?page=3입니다.
• back 메서드는 세션 기록에서 이전 항목으로 이동합니다.
• 이동 후 페이지 URL: http://example.com/example.html?page=1
• 상태: { page: 1 }
• 콘솔 출력: "location: http://example.com/example.html?page=1, state: {"page":1}"history.back();
• 현재 페이지 URL은 http://example.com/example.html?page=1입니다.
• back 메서드는 세션 기록에서 이전 항목으로 이동합니다.
• 이동 후 페이지 URL: http://example.com/example.html
• 상태: null
• 콘솔 출력: "location: http://example.com/example.html, state: null"history.go(2);
• 현재 페이지 URL은 http://example.com/example.html입니다.
• go 메서드는 세션 기록에서 지정된 위치로 이동합니다. 2는 두 단계 앞으로 이동하는 것을 의미합니다.
• 이동 후 페이지 URL: http://example.com/example.html?page=3
• 상태: { page: 3 }
• 콘솔 출력: "location: http://example.com/example.html?page=3, state: {"page":3}"
window.location 객체는 현재 문서의 URL을 나타내며, URL과 관련된 여러 정보를 얻고 변경할 수 있는 속성과 메서드를 제공합니다.
window는 브라우저 환경에서 자바스크립트 코드가 실행될 때 제공되는 전역 객체.
window 객체의 모든 속성과 메서드는 전역 네임스페이스에 존재하므로 window 생략 가능.
window.location.href
현재 페이지의 전체 URL을 반환하거나 설정합니다.
console.log(window.location.href); // "https://www.example.com/path/page.html"
window.location.href = "https://www.example.com/newpage.html"; // 페이지 이동
window.location.protocol
URL의 프로토콜 부분을 반환합니다. (예: “http:”, “https:”)
console.log(window.location.protocol); // "https:"
window.location.host
호스트 이름과 포트 번호를 반환합니다. (예: “www.example.com:80”)
console.log(window.location.host); // "www.example.com"
✅ 표준 포트 번호 생략
HTTP (포트 80) > HTTPS (포트 443)
표준 포트를 사용할 경우 window.location.host는 포트 번호를 포함하지 않고 호스트 이름만 반환.
window.location.hostname
호스트 이름을 반환합니다. (예: “www.example.com”)
console.log(window.location.hostname); // "www.example.com"
window.location.port
포트 번호를 반환합니다. (예: “80”, “443”)
console.log(window.location.port); // "443"
window.location.pathname
URL의 경로 부분을 반환합니다. (예: “/path/page.html”)
console.log(window.location.pathname); // "/path/page.html"
window.location.search
URL의 쿼리 문자열 부분을 반환합니다. (예: “?name=value”)
console.log(window.location.search); // "?name=value"
window.location.hash
URL의 해시(#) 부분을 반환합니다. (예: “#section1”)
console.log(window.location.hash); // "#section1"
window.location.origin
현재 URL의 원점을 반환합니다. (예: “https://www.example.com”)
console.log(window.location.origin); // "https://www.example.com"
window.location.assign(url)
지정된 URL로 이동합니다.
window.location.assign("https://www.example.com");
window.location.replace(url)
지정된 URL로 이동하며, 현재 페이지를 브라우저 히스토리에서 제거합니다. 즉, 뒤로 가기 버튼을 눌렀을 때 replace 메서드로 이동하기 전 페이지로 돌아갈 수 없습니다.
window.location.replace("https://www.example.com");
window.location.reload(forceReload)
현재 문서를 다시 로드합니다. forceReload가 true이면 서버에서 새로고침을 강제하고, false이면 캐시된 버전을 사용할 수 있습니다.
window.location.reload(); // 기본: 캐시된 버전을 사용할 수 있음
window.location.reload(true); // 서버에서 새로고침을 강제
document 객체는 웹 페이지의 콘텐츠를 조작할 수 있는 API를 제공합니다. 이는 DOM(Document Object Model)을 통해 HTML 문서 구조를 표현하며, JavaScript로 웹 페이지를 동적으로 변경할 수 있게 해줍니다. document 객체를 사용하여 웹 페이지의 요소를 탐색하고, 수정하고, 이벤트를 추가할 수 있습니다.
URL 관련
document.location
window.location 객체와 동일하게 현재 문서의 URL을 반환하거나 설정합니다.
console.log(document.location.href); // 현재 URL을 출력
document.location.href = "https://www.example.com"; // 새 URL로 이동
document.referrer
현재 문서를 참조한 문서의 URL을 반환합니다.
console.log(document.referrer); // 사용자가 이 페이지로 오기 전의 페이지 URL을 출력
✏️ URL, URI, URN 개념 정리
- URI (Uniform Resource Identifier): 웹 상의 자원을 식별하는 문자열입니다. URI는 URL과 URN을 포함하는 상위 개념입니다. URI는 특정 리소스에 대한 식별 정보를 제공합니다.
- URL (Uniform Resource Locator): 자원의 위치를 나타내는 URI의 한 형태로, 프로토콜, 호스트, 경로 등 자원의 접근 방법을 포함합니다. 예: https://www.example.com/path/to/resource.
- URN (Uniform Resource Name): 자원의 이름을 나타내는 URI의 한 형태로, 자원의 위치와 관계없이 고유하게 식별합니다. 예: urn:isbn:0451450523.
참고 - difference-between-uri-url
참고 - URI
URL(Uniform Resource Locator)은 웹 상의 자원을 식별하는 문자열입니다. URL은 여러 부분으로 구성되며, 각 부분은 특정한 역할을 합니다.
프로토콜 (Scheme)
자원에 접근하기 위해 사용하는 프로토콜을 지정합니다.
예: http, https, ftp
예시: https://
호스트 (Host)
자원이 위치한 서버의 도메인 이름 또는 IP 주소를 지정합니다.
예: www.example.com
예시: https://www.example.com
포트 (Port)
서버의 특정 네트워크 포트를 지정합니다. 기본 포트를 사용하는 경우 생략될 수 있습니다.
예: :80, :443
예시: https://www.example.com:443
경로 (Path)
서버 상의 특정 자원에 대한 경로를 지정합니다.
예: /path/to/resource
예시: https://www.example.com/path/to/resource
쿼리 문자열 (Query String)
자원에 대한 추가적인 매개변수를 지정합니다. ?로 시작하며 &로 구분됩니다.
예: ?key1=value1&key2=value2
예시: https://www.example.com/path/to/resource?key1=value1&key2=value2
프래그먼트 (Fragment)
문서 내의 특정 부분을 지정합니다. #로 시작합니다.
예: #section1
예시: https://www.example.com/path/to/resource?key1=value1&key2=value2#section1
전체 URL 예시: https://www.example.com:443/path/to/resource?key1=value1&key2=value2#section1
• 프로토콜: https
• 호스트: www.example.com
• 포트: 443
• 경로: /path/to/resource
• 쿼리 문자열: ?key1=value1&key2=value2
• 프래그먼트: #section1
정리 - 실제 예시
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>URL Parts Example</title>
</head>
<body>
<button onclick="showURLParts()">Show URL Parts</button>
<script>
function showURLParts() {
console.log("전체 URL: " + location.href);
console.log("프로토콜: " + location.protocol);
console.log("호스트: " + location.host);
console.log("호스트 이름: " + location.hostname);
console.log("포트: " + location.port);
console.log("경로: " + location.pathname);
console.log("쿼리 문자열: " + location.search);
console.log("프래그먼트: " + location.hash);
}
</script>
</body>
</html>
React에서는 React Router를 사용하여 History API를 쉽게 사용할 수 있습니다. React Router는 SPA에서 클라이언트 측 라우팅을 처리하는 데 사용됩니다.
import React from "react";
import { BrowserRouter as Router, Route, Switch, Link } from "react-router-dom";
function Home() {
return <h1>Home</h1>;
}
function About() {
return <h1>About</h1>;
}
function Contact() {
return <h1>Contact</h1>;
}
function App() {
return (
<Router>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/contact">Contact</Link>
</nav>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
</Switch>
</Router>
);
}
export default App;
Next.js는 서버 사이드 렌더링(SSR)을 지원하는 React 프레임워크입니다. Next.js에서는 기본적으로 페이지 간 이동이 서버 측에서 처리되지만, 클라이언트 측 네비게이션을 위해 next/router, next/navigation을 사용할 수 있습니다.
next/router를 사용합니다.
import { useRouter } from "next/router";
function Home() {
const router = useRouter();
const navigateTo = (url) => {
router.push(url);
};
return (
<div>
<h1>Home</h1>
<button onClick={() => navigateTo("/about")}>Go to About</button>
<button onClick={() => navigateTo("/contact")}>Go to Contact</button>
</div>
);
}
export default Home;
참고 - Next.js 공식 문서 Page Router/useRouter
next/navigation을 사용합니다.
"use client";
import { useRouter } from "next/navigation";
export default function Page() {
const router = useRouter();
return (
<button type="button" onClick={() => router.push("/dashboard")}>
Dashboard
</button>
);
}
참고 - Next.js 공식 문서 App Router/useRouter
추가하면 좋은 부분이나 잘못된 점이 있다면 댓글 남겨주세요. 감사합니다 :)