駆け出しフロントエンジニアがコンソール上で学んだブラウザバック。（1/n）

## この記事の対象者
　自分と、初学者向けです。
　コンソール上で確認したことをベースに記載していますので、内容に間違いなどありましたらご教示いただけますと幸いです。

## 目次＆目的
- ブラウザバックって何だろう
- ブラウザバックする方法を知る
-----この記事はここまで-----
- ブラウザバックの検知方法を知る
- ブラウザバックの中止方法を知る

## ブラウザバックって何だろう
～とあるNextjsとTypeScriptの現場～

？？「ブラウザバックのイベント実装できる？」
自分「（やったことないけど）大丈夫ですよ」

　はい、無理でした。
　基礎もわかってないのにNextjs（というかReact）のブラウザバックをハンドリングできるわけないですね。
　私の人生をブラウザバックしたいところですが、基礎を学んで前に進むしかないようです。

　Chromeで「ブラウザバック　仕組み」で検索すると下記の記事が最初にヒットしました。
　　　https://hylom.net/2020/10/25/web-history-api-guide/
　この記事を必要なところだけほぼそのまま引用させていただくと
- Webブラウザ上では、閲覧履歴をスタックとして管理している。
- スタックはWebブラウザのウィンドウやタブごとに用意されている。
- ページの進む/戻る操作ではこの履歴スタック自体は変更されず、履歴スタック上の現在位置のみが変更される。
- 閲覧履歴を実際に管理しているのはhistoryAPI。

　ということでした。言われてみればわかりやすい仕組みなのですね。共有ありがとうございます。
　ページを戻ることを「ブラウザバック」と言いますが、進むことは「ブラウザフォワード」と聞きませんね。ちなみにChromeのヒット件数はブラウザバック：4千万件、ブラウザフォワード：4十万件と100倍の差がありました。

　実際にChromeでconsole.log(window.history)をすると色々な表示がされました。
 
↓　こういうのとか（[[Prototype]]:Historyは非展開。「b」で調べた検索結果の表示ページ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367741/c8231ca6-d016-fbc4-e9d3-ae1d020f0bc6.png)

↓　こういうの（[[Prototype]]:Historyは展開）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367741/f67f322e-d7a6-580f-db39-ff171b72b7ec.png)

これを見て、以下の感想を持ちました。
- historyの構造はpushstateとreplaceが1次にあるかないか、など1種類じゃないみたい
- stateには検索結果ページだと情報が入るみたい
- pushState、replaceStateってなんだろう（ほかのも）

ここから、とりあえず手当たり次第にlogを出してみて、以下がわかりました。
- length　→　今開いているタブにスタックされている履歴
- 体感でしかわかってなかったけど、タブ間でスタックされている履歴は別（lengthの数＝タブが管理している履歴数。新規タブだとlength=1）

ここからブラウザバック実装関係に絞って深堀っていきます。

（脱線しますが、Chromeの閲覧履歴（Ctrl+H）は上記のlengthで表示される履歴が蓄積されたものに見えます。ウインドウ用の閲覧履歴も蓄積されていて、そちらはhistoryと違う方法でアクセスできるのでしょうか。。。？気になりますが今回は関係ないのでスルー）

## ブラウザバックする方法を知る
　Historyに入っているメソッドをコンソール上で試してみると、以下の挙動でした。
- history.back():（あれば）前のページに戻る　→　ブラウザバック
- history.forward():（あれば）次のページに進む
- history.go(num?):（あれば）引数だけページを移動する

　ブラウザが動く仕組みはこれのようですし、目的のブラウザバックする方法はわかりました。
　ちなみに、Chromeだとタブの履歴はブラウザの戻るボタンを右クリックすると確認できます。
　また、go()の引数に何も指定しないとリロード(F5)になります。

　動く仕組みはわかりましたので、ついでに他のメソッドも見ていきます。
　ドキュメントはこちらも参考にしております
　MDN　https://developer.mozilla.org/ja/docs/Web/API/History/replaceState
### history.replaceState(state, unused, url?)
  現在ページの履歴のスタックのURLを書き換えられます。自動でリロードはされません。
- state →　オブジェクト値を保持させられる。
- unused →　常に""を指定
- url →　書き換えたいURL（ドメイン以外）
  ということですね。動線確保に使うんでしょうね。
  
　リロードすると、書き換えたURLに遷移します。
　また、書き換えられる前のURLは戻るや進むボタンでは移動できません。
　スタックを直接書き換えたからですね。エッセンシャルなHPでは使えそうです（クレカ入力とか）

### history.pushState(state, unused, url?)
　履歴のスタックに指定したurlをpushする。そのままですね。自動でリロードはされません。
　引数はreplaceStateと一緒です。
　ブラウザバックで避けては通れないメソッドのためしっかり検証します。
　下記のAPIで検証させていただいたところ
　 　　https://jsonplaceholder
　pushしたurlと、一つ前になったurlの内容が同じになる（浅いコピー）ようですね。

url末尾1（最初のページ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367741/d0a1d3bc-acbb-be8b-ded7-e9df92c616bf.png)

url末尾2に移動して、history.pushState({id:1},"",3)を実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367741/5789e76a-808a-3eea-8ba4-37c6fceea22e.png)

リロード(id:1がstateにsetされている)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367741/514d5f7c-777d-778d-5d5d-b36fe6a4c905.png)

url末尾2にブラウザバック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367741/3aa69c36-9261-3271-799c-63d59e81063e.png)

　また、最後のurlに何も指定しなければ全く同じページが作成されます。
　こちらが普通の使い方ですかね。

url末尾1（最初のページ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367741/d0a1d3bc-acbb-be8b-ded7-e9df92c616bf.png)

url末尾2に移動して、history.pushState({id:2},"")を実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367741/f86889f8-f6ea-a8f4-d305-a3eb9d0a8f9a.png)

リロード(id:2がstateにsetされている)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367741/53546324-0f4f-daec-4e3d-0bb09ea5a950.png)

url末尾2にブラウザバック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367741/9ace7a58-e065-a161-4074-83ec447f3a80.png)

　長くなったのでユースケースをおさらいして締めます。

　間違ってブラウザバックをしたAさんを助けてあげたいと考えると、

1.Aさんがブラウザバックする
↓
2.ブラウザバックを検知する
↓
3.Aさんがブラウザバックするかどうか選択
↓
4.ブラウザバックしないを選択した場合に現在の画面を保持したい
↓
5.現在の画面のURLを戻り先に加えて、あたかも現在の画面を移動していないようにしよう

　この5で使うのがpushStateになりそうです。

　戻るページを作成するものと勘違いしていたので、スタックにpushするにも関わらず現在ページ（スタックの一番上）の一つ前にページが作られるのか？と思ってたんですが、実際は先頭に現在ページの浅いコピーをpushするということですね。多分。

 2/2へ続きます。