Skip to content

Commit

Permalink
[ko] Working with the History API 번역 업데이트
Browse files Browse the repository at this point in the history
  • Loading branch information
effozen committed Dec 18, 2024
1 parent c4bd9c6 commit 8373969
Showing 1 changed file with 135 additions and 54 deletions.
189 changes: 135 additions & 54 deletions files/ko/web/api/history_api/working_with_the_history_api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,101 +7,182 @@ l10n:

{{DefaultAPISidebar("History API")}}

{{DOMxRef("History.pushState","pushState()")}} 및 {{DOMxRef("History.replaceState","replaceState()")}}메서드는 각각 히스토리 항목을 추가하고 수정합니다. 이 메서드들은 {{domxref("Window/popstate_event", "popstate")}} 이벤트와 함께 작동합니다.
History API는 웹사이트가 브라우저의 세션 기록과 상호작용할 수 있게 해줍니다. 세션 기록이란 사용자가 특정 창에서 방문한 페이지들의 목록을 말합니다. 예를 들어 사용자가 링크를 클릭하여 새로운 페이지를 방문하면, 그 새로운 페이지들이 세션 기록에 추가됩니다. 사용자는 브라우저의 "뒤로" 및 "앞으로" 버튼을 사용하여 기록을 앞뒤로 이동할 수도 있습니다.

## 히스토리 항목 추가 및 수정
History API에서 정의된 주요 인터페이스는 {{domxref("History")}} 인터페이스이며, 이 인터페이스는 두 가지 전혀 다른 메서드 집합을 정의합니다:

{{DOMxRef("History.pushState","pushState()")}}을 사용하면 상태를 변경한 후 생성된 {{domxref("XMLHttpRequest")}}객체의 HTTP 헤더에 사용되는 리퍼러가 변경됩니다. 리퍼러는 {{domxref("XMLHttpRequest")}} 객체를 생성할 때 창이 `this`인 문서의 URL이 됩니다.
1. 세션 기록의 페이지로 이동하는 메서드:

### pushState() 메서드 예제
- {{domxref("History.back()")}}
- {{domxref("History.forward()")}}
- {{domxref("History.go()")}}

`https://mozilla.org/foo.html`이 다음 JavaScript 코드를 실행한다고 가정합니다.
2. 세션 기록을 수정하는 메서드:

```js
const stateObj = {
foo: "bar",
};

history.pushState(stateObj, "page 2", "bar.html");
```
- {{domxref("History.pushState()")}}
- {{domxref("History.replaceState()")}}

이렇게 하면 URL 표시줄에 `https://mozilla.org/bar.html`이 표시되지만, 브라우저가 `bar.html`를 로드하거나 `bar.html`이 존재하는지 확인하지는 않습니다.
이 가이드에서는 더 복잡한 동작을 가지는 두 번째 메서드 집합에만 초점을 맞출 것입니다.

이제 사용자가 `https://google.com`로 이동한 다음 **뒤로가기**버튼을 클릭한다고 가정해 보겠습니다. 이 시점에서 URL 표시줄에 `https://mozilla.org/bar.html`이 표시되고 `history.state``stateObj`가 포함됩니다. 페이지가 새로고침되었기 때문에 `popstate` 이벤트는 발생하지 않습니다. 페이지 자체는 `bar.html`처럼 보일 것입니다.
`pushState()` 메서드는 세션 기록에 새 항목을 추가하고, `replaceState()` 메서드는 현재 페이지의 세션 기록 항목을 업데이트합니다. 이 두 메서드는 모두 `state` 매개변수를 사용하며, 이는 어떤 {{Glossary("Serializable_object", "직렬화 가능한 객체")}}도 포함할 수 있습니다. 브라우저가 이 히스토리 항목으로 네비게이트할 때, 브라우저는 이 항목과 연관된 상태 객체를 포함하는 {{domxref("Window.popstate_event", "popstate")}} 이벤트를 발생시킵니다.

사용자가 **뒤로가기**를 다시 한 번 클릭하면, URL이 `https://mozilla.org/foo.html`로 변경되고 이번에는 문서에 `null` 상태 객체가 포함된 `popstate` 이벤트가 발생합니다. 여기서도 뒤로 돌아간다고 해서 문서의 내용이 이전 단계의 내용과 바뀌지는 않지만 문서가 `popstate` 이벤트를 수신하면 내용을 수동으로 업데이트할 수 있습니다.
이 API의 주요 목적은 {{Glossary("SPA", "싱글 페이지 애플리케이션")}}와 같은 웹사이트를 지원하는 것입니다. 이러한 웹사이트는 {{domxref("Window/fetch", "fetch()")}}와 같은 JavaScript API를 사용하여 전체 새로운 페이지를 로드하는 대신 새로운 콘텐츠로 페이지를 업데이트합니다.

### pushState() 메서드
## 싱글 페이지 애플리케이션과 세션 기록

`pushState()`**state object**, **title**(현재 무시됨), **URL**(선택사항)의 세 가지 매개변수를 가집니다.
전통적으로, 웹사이트는 페이지 모음으로 구현됩니다. 사용자가 링크를 클릭하여 사이트의 다른 부분으로 이동할 때마다 브라우저는 매번 완전한 새 페이지를 로드합니다.

이 세 가지 매개변수를 각각 자세히 살펴보겠습니다.
이는 많은 사이트에 적합하지만, 몇 가지 단점이 있을 수 있습니다:

- **state object**
- : 상태 객체는 `pushState()`에 의해 생성된 새 기록 항목과 연관된 JavaScript 객체입니다. 사용자가 새 상태로 이동할 때마다 `popstate` 이벤트가 발생하고 이벤트의 `state` 속성에는 기록 항목의 상태 개체 복사본이 포함됩니다. 상태 객체는 직렬화할 수 있는 모든 것이 될 수 있습니다. 상태 객체는 사용자가 브라우저를 재시작한 후 복원할 수 있도록 사용자의 디스크에 저장되므로 상태 객체의 직렬화된 표현에 640k라는 크기 제한을 적용합니다. 직렬화된 표현이 이보다 큰 상태 객체를 `pushState()`에 전달하면 메서드는 예외를 던집니다. 이보다 더 많은 공간이 필요한 경우, `sessionStorage` 또는 `localStorage`사용을 권장합니다.
- **title**
- : [Safari를 제외한 모든 브라우저는 현재 이 매개변수를 무시](https://github.com/whatwg/html/issues/2174)하지만 향후 이 매개변수를 사용할 수 있습니다. 여기에 빈 문자열을 전달하면 향후 메서드 변경에 대비하여 안전할 것입니다. 또는 이동하려는 상태에 대한 짧은 제목을 전달할 수도 있습니다.
- **URL**
- : 새 기록 항목의 URL은 이 매개변수에 의해 지정됩니다. 브라우저는 `pushState()`를 호출한 후에는 이 URL을 로드하려고 시도하지 않지만, 사용자가 브라우저를 다시 시작한 후와 같이 나중에 URL을 로드하려고 시도할 수 있습니다. 새 URL은 절대 URL일 필요는 없으며, 상대 URL인 경우 현재 URL을 기준으로 확인됩니다. 새 URL은 현재 URL과 동일한 출처여야 합니다. 그렇지 않으면 `pushState()`가 예외를 던집니다. 이 매개변수는 선택 사항이며, 지정하지 않으면 문서의 현재 URL로 설정됩니다.
- 페이지의 일부만 업데이트해야 할 때마다 전체 페이지를 로드하는 것은 비효율적일 수 있습니다.
- 페이지 간 네비게이션 시 애플리케이션 상태를 유지하기 어렵습니다.

어떤 의미에서 `pushState()`를 호출하는 것은 현재 문서와 연결된 다른 히스토리 항목도 생성하고 활성화한다는 점에서 `window.location = "#foo"`를 설정하는 것과 유사합니다.
이러한 이유로 웹 애플리케이션에서 인기 있는 패턴은 {{Glossary("SPA", "싱글 페이지 애플리케이션")}}(SPA)이며, 이 경우 사이트는 단일 페이지로 구성되고 사용자가 링크를 클릭할 때 페이지는 다음과 같이 동작합니다:

하지만 `pushState()`에는 몇 가지 장점이 있습니다.
1. 새 페이지를 로드하는 기본 동작을 방지합니다.
2. {{domxref("Window/fetch", "Fetches", "", "nocode")}} 새로운 콘텐츠를 가져옵니다.
3. 새로운 콘텐츠로 페이지를 업데이트합니다.

- 새 URL은 현재 URL과 동일한 원본에 있는 모든 URL이 될 수 있습니다. 반면, `window.location`을 설정하면 해시만 수정하는 경우에는 동일한 {{ domxref("document") }}로 유지됩니다.
- 원하지 않는 경우 URL을 변경하지 않아도 됩니다. 반대로, `window.location = "#foo";`를 설정하면 현재 해시가 `#foo`가 아닌 경우에만 새 기록 항목이 생성됩니다.
- 임의의 데이터를 새 기록 항목에 연결할 수 있습니다. 해시 기반 접근 방식을 사용하면 모든 관련 데이터를 짧은 문자열로 인코딩해야 합니다.
- 만약 이후 `title` 브라우저에서 제목을 사용하는 경우, 해시와 무관하게 이 데이터를 활용할 수 있습니다.
예를 들어:

새 URL이 이전 URL과 해시만 다르더라도 `pushState()`는 이벤트를 발생시키지 않는다는 점에 유의해야 합니다.
```js
document.addEventListener("click", async (event) => {
const creature = event.target.getAttribute("data-creature");
if (creature) {
// 새 페이지가 로드되지 않도록 방지
event.preventDefault();
try {
// 새로운 콘텐츠 가져오기
const response = await fetch(`creatures/${creature}.json`);
const json = await response.json();
// 새로운 콘텐츠로 페이지 업데이트
displayContent(json);
} catch (err) {
console.error(err);
}
}
});
```

다른 문서에서는 `null` 네임스페이스 URI를 가진 요소를 생성합니다.
이 클릭 핸들러에서, 링크에 `"data-creature"` 데이터 속성이 포함되어 있다면, 해당 속성의 값을 사용하여 페이지의 새로운 콘텐츠를 포함하는 JSON 파일을 가져옵니다.

### replaceState() 메서드
JSON 파일은 다음과 같을 수 있습니다:

`history.replaceState()``history.pushState()`와 똑같이 작동하지만, `replaceState()`는 새 항목을 만드는 대신 현재 기록 항목을 수정한다는 점이 다릅니다. 이렇게 해도 전역 브라우저 기록에 새 항목이 생성되는 것을 막지는 못합니다.
```json
{
"description": "대머리 독수리는 실제로 대머리가 아닙니다.",
"image": {
"src": "images/eagle.jpg",
"alt": "대머리 독수리"
},
"name": "독수리"
}
```

`replaceState()`는 특정 사용자 작업에 대한 응답으로 현재 기록 항목의 상태 개체 또는 URL을 업데이트하려는 경우에 특히 유용합니다.
우리의 `displayContent()` 함수는 JSON으로 페이지를 업데이트합니다:

### replaceState() 메서드 예제
```js
// 새로운 콘텐츠으로 페이지 업데이트
function displayContent(content) {
document.title = `생물: ${content.name}`;

`https://mozilla.org/foo.html`이 다음 JavaScript 코드를 실행한다고 가정합니다.
const description = document.querySelector("#description");
description.textContent = content.description;

```js
const stateObj = {
foo: "bar",
};
history.pushState(stateObj, "page 2", "bar.html");
const photo = document.querySelector("#photo");
photo.setAttribute("src", content.image.src);
photo.setAttribute("alt", content.image.alt);
}
```

위의 두 줄에 대한 설명은 [pushState() 메서드 예제](<#pushState()_메서드_예제>) 섹션에서 확인할 수 있습니다.
문제는 이것이 브라우저의 "뒤로" 및 "앞으로" 버튼의 예상 동작을 깨뜨린다는 것입니다.

사용자의 관점에서는 링크를 클릭하고 페이지가 업데이트되었으므로 새 페이지처럼 보입니다. 그런 다음 브라우저의 "뒤로" 버튼을 누르면 링크를 클릭하기 전 상태로 돌아가길 기대합니다.

하지만 브라우저의 관점에서는 마지막 링크가 새 페이지를 로드하지 않았으므로 "뒤로" 버튼을 누르면 사용자가 SPA를 열기 전에 로드된 페이지로 이동하게 됩니다.

다음으로 `https://mozilla.org/bar.html`이 다음 JavaScript 코드를 실행한다고 가정합니다.
이것이 `pushState()`, `replaceState()`, 그리고 `popstate` 이벤트가 해결하는 문제입니다. 이들은 역사 항목을 합성하고, 현재 세션 기록 항목이 이러한 항목 중 하나로 변경될 때(예를 들어, 사용자가 "뒤로" 또는 "앞으로" 버튼을 눌렀을 때)를 알 수 있게 해줍니다.

## `pushState()` 사용하기

위의 클릭 핸들러에 역사 항목을 추가할 수 있습니다:

```js
history.replaceState(stateObj, "page 3", "bar2.html");
document.addEventListener("click", async (event) => {
const creature = event.target.getAttribute("data-creature");
if (creature) {
event.preventDefault();
try {
const response = await fetch(`creatures/${creature}.json`);
const json = await response.json();
displayContent(json);
// 새로운 역사 항목을 추가합니다.
// 이는 새 페이지를 로드하는 것을 시뮬레이션합니다.
history.pushState(json, "", creature);
} catch (err) {
console.error(err);
}
}
});
```

이렇게 하면 URL 표시줄에 `https://mozilla.org/bar2.html`이 표시되지만 브라우저가 `bar2.html`를 로드하거나 `bar2.html`이 존재하는지 확인하지는 않습니다.
여기서 우리는 세 가지 인수로 `pushState()`를 호출하고 있습니다:

- `json`: 방금 가져온 콘텐츠입니다. 이는 역사 항목과 함께 저장되며, 나중에 사용자가 A로 네비게이션할 때 `popstate` 이벤트 핸들러에 전달되는 인수의 {{domxref("PopStateEvent.state", "state")}} 속성으로 포함됩니다.
- `""`: 이는 레거시 사이트와의 하위 호환성을 위해 필요하며, 항상 빈 문자열이어야 합니다.
- `creature`: 이는 항목의 URL로 사용됩니다. 브라우저의 URL 표시줄에 표시되며, 페이지가 수행하는 모든 HTTP 요청에서 {{httpheader("Referer")}} 헤더의 값으로 사용됩니다. 이는 페이지와 {{Glossary("Same-origin policy", "동일 출처 정책")}}이어야 합니다.

이제 사용자가 `https://www.microsoft.com`로 이동한 다음 **뒤로가기**버튼을 클릭한다고 가정하겠습니다. 이 시점에서 URL 표시줄에 `https://mozilla.org/bar2.html`이 표시됩니다. 이제 사용자가 **뒤로가기**버튼을 다시 클릭하면 URL 표시줄에 `https://mozilla.org/foo.html`가 표시되고 `bar.html`이 완전히 우회됩니다.
## `popstate` 이벤트 사용하기

### popstate 이벤트
사용자가 다음과 같이 동작한다고 가정해 봅시다:

활성 기록 항목이 변경될 때마다 창에 `popstate` 이벤트가 전송됩니다. 활성화 중인 기록 항목이 {{DOMxRef("History.pushState","pushState")}} 호출에 의해 생성되었거나 {{DOMxRef("History.replaceState","replaceState")}} 호출의 영향을 받은 경우, `popstate` 이벤트의 `state` 속성에는 기록 항목의 상태 객체 복사본이 포함됩니다.
1. SPA에서 링크를 클릭하여 페이지를 업데이트하고 `pushState()`를 사용하여 역사 항목 A를 추가합니다.
2. SPA에서 다른 링크를 클릭하여 페이지를 업데이트하고 `pushState()`를 사용하여 역사 항목 B를 추가합니다.
3. "뒤로" 버튼을 누릅니다.

샘플 사용법은 {{domxref("Window/popstate_event", "popstate")}}에서 확인하시면 됩니다.
이제 새로운 현재 역사 항목은 A가 되므로, 브라우저는 `popstate` 이벤트를 발생시키고, 이벤트 핸들러 인수는 A로 네비게이션할 때 `pushState()`에 전달했던 JSON을 포함합니다. 이는 다음과 같은 이벤트 핸들러를 사용하여 올바른 콘텐츠를 복원할 수 있음을 의미합니다:

```js
// 앞으로/뒤로 버튼 처리
window.addEventListener("popstate", (event) => {
// 상태가 제공된 경우, "시뮬레이션된" 페이지가 있으며 현재 페이지를 업데이트합니다.
if (event.state) {
// 이전 페이지 로드를 시뮬레이션합니다.
displayContent(event.state);
}
});
```

### 현재 상태 읽기
## `replaceState()` 사용하기

페이지가 로드될 때 non-null 상태가 아닌 객체가 있을 수 있습니다. 예를 들어 페이지에서 상태 객체를 설정한 후 ({{DOMxRef("History.pushState","pushState()")}} 또는 {{DOMxRef("History.replaceState","replaceState()")}}사용)사용자가 브라우저를 재시작하는 경우 이런 일이 발생할 수 있습니다. 페이지가 다시 로드되면 페이지에 `onload` 이벤트가 수신되지만 `popstate` 이벤트는 수신되지 않습니다. 그러나 {{DOMxRef("History.state","history.state")}} 속성을 읽으면 `popstate`가 발생했을 때 얻을 수 있는 상태 객체를 다시 얻을 수 있습니다.
추가해야 할 한 가지가 더 있습니다. 사용자가 SPA를 로드할 때, 브라우저는 역사 항목을 추가합니다. 이 항목은 실제 페이지 로드였기 때문에 상태가 연관되어 있지 않습니다. 따라서 사용자가 다음과 같이 동작한다고 가정해 봅시다:

다음과 같이 {{DOMxRef("History.state","history.state")}} 속성을 사용하여 `popstate` 이벤트를 기다리지 않고 현재 기록 항목의 상태를 읽을 수 있습니다.
1. SPA를 로드합니다: 브라우저는 역사 항목을 추가합니다.
2. SPA 내의 링크를 클릭하여 페이지를 업데이트하고 `pushState()`를 사용하여 역사 항목을 추가합니다.
3. "뒤로" 버튼을 누릅니다.

이제 사용자는 SPA의 초기 상태로 돌아가길 원하지만, 이는 같은 문서 내에서의 네비게이션이기 때문에 페이지가 다시 로드되지 않으며, 초기 페이지의 역사 항목에는 상태가 없기 때문에 `popstate`를 사용하여 복원할 수 없습니다.

해결책은 `replaceState()`를 사용하여 초기 페이지의 상태 객체를 설정하는 것입니다. 예를 들어:

```js
const currentState = history.state;
// 페이지 로드 시 상태를 생성하고 현재 기록을 교체합니다.
const image = document.querySelector("#photo");
const initialState = {
description: document.querySelector("#description").textContent,
image: {
src: image.getAttribute("src"),
alt: image.getAttribute("alt"),
},
name: "",
};
history.replaceState(initialState, "", document.location.href);
```

페이지 로드 시, 사용자가 SPA의 시작 지점으로 돌아갔을 때 복원할 모든 페이지의 부분을 수집합니다. 이는 다른 네비게이션을 처리할 때 가져오는 JSON과 동일한 구조를 가지고 있습니다. 우리는 이 `initialState` 객체를 `replaceState()`에 전달하여 현재 역사 항목에 상태 객체를 효과적으로 추가합니다.

사용자가 시작 지점으로 돌아가면, `popstate` 이벤트는 이 초기 상태를 포함하게 되며, 우리는 `displayContent()` 함수를 사용하여 페이지를 업데이트할 수 있습니다.

## 같이 보기

- [History API](/ko/docs/Web/API/History_API)
Expand Down

0 comments on commit 8373969

Please sign in to comment.