SPAとは何か？

## はじめに
これまで何となく `fetch` や `SPA` という言葉を使っていましたが、`React` での開発を通じて、それらがどう貢献しているのかはよく分かっていませんでした。
そこで今回、『プロになるためのWeb技術入門』を読んで基礎から学び直した内容を、自分なりに整理してまとめます。

https://www.amazon.co.jp/%EF%BC%BB%E6%94%B9%E8%A8%82%E6%96%B0%E7%89%88%EF%BC%BD%E3%83%97%E3%83%AD%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AEWeb%E6%8A%80%E8%A1%93%E5%85%A5%E9%96%80-%E5%B0%8F%E6%A3%AE-%E8%A3%95%E4%BB%8B/dp/4297145715/ref=asc_df_4297145715?mcid=3e771cea86eb31a59fa1de8704335b45&th=1&psc=1&tag=jpgo-22&linkCode=df0&hvadid=707442440784&hvpos=&hvnetw=g&hvrand=10374524567018617644&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009309&hvtargid=pla-2367318999961&psc=1&gad_source=1



## fetchとは
`fetch` は、JavaScriptで非同期通信を行うための関数で、主にJSON形式のデータをやり取りするのに使われます。

従来のWebアプリでは、サーバーからHTMLを丸ごと受け取っていましたが、`fetch` を使えば必要なデータだけを取得し、画面に反映できるため、表示速度や操作性が大きく向上します。

:::note
**XHR（XMLHttpRequest）との違い**
以前は `XMLHttpRequest（XHR）` を使って非同期通信を行っていましたが、`fetch` はPromiseをベースで書けるため、非同期処理のコードがシンプルに書けます
:::

## SPAとは
SPAは、 `Single Page Application` の略称です。
従来のWebアプリでは、ユーザーの操作ごとにサーバーから **HTML全体を再取得** していたため、画面が再読み込みされるたびに白くなったり遅延が発生していました。
また、POSTの再送信を防ぐため、 `PRG（Post-Redirect-Get）` パターンを使う必要があり、画面の切り替えに時間がかかっていました。

しかし、`fetch` を用いた `SPA` を使うことによりJSON形式でレスポンスでき、結果をそのままJavaScriptによって描画するため、表示が高速化されます。

:::note
**PRG（Post-Redirect-Get）とは**
>フォームの送信（POST）後に、そのまま結果画面を表示すると「再読み込み時に再送信されてしまう」という問題が起きます。
それを防ぐために、POST後に一度リダイレクト（Redirect）し、GETで最終的な画面を表示するパターンです。

目的は、ユーザーの「再読み込み」操作で、同じPOSTリクエストが再送されて、**同じデータが複数登録される** ことを防ぐことです。
:::

## SPAにおけるURLの課題
`SPA` では、JavaScriptにより「画面遷移しているように見える」だけで、**<font color='red'>実際のURLが変わらない</font>** という特性があります。
このデメリットは以下のようなものが挙げられます。

- 特定の画面をブックマークとしても、対象の画面が保存できない
- ブラウザ上の戻る・進むボタンが機能しない

これらのデメリットに対して２つの解決方法があります。

### 1. フラグメント
この課題への解決策の１つが 、<font color='blue'>フラグメント（URLの # のあとに付く部分）</font>の活用です。
例えば次のような形式です。
```zsh
https://example.com/#profile
```

ブラウザのアドレスバーでフラグメント部分（#profile）が変化しても、ブラウザには認識されますがサーバーには送信されません。
ブラウザ側では、JavaScriptの `location.hash` を使って、フラグメントの変化を検知・監視することができます。

ただし、フラグメントを使う方法には、以下の弱点があります。

:::note warn
- URLと画面が１対１に対応していないため、Googleなどの検索エンジンがこの部分を読み取れないことがあり、検索結果に表示されにくくなる（SEOに弱い）
- URLのフラグメントが変わっても、サーバーではその違いが分からないため、他の人に共有しても同一画面が再現されない可能性がある
:::


### 2. History API
そこで使われるのが `History API` です。
`history.pushState()` を使うことで、サーバーへのリクエストなしに、URLを変更したように見せかけながらページ遷移が可能になります。

これにより、以下のメリットが挙げられます。

- URLと画面が１対１で対応
- URLごとのブックマークが可能
- 戻る・進むボタンも機能する
- SEO対策にも効果的

このように、`History API`を用いることで、`フラグメント` のデメリットを克服することができるようになりました。

## Reactにおけるルーティング


また、`React`ではこの`History API`を活用した`React Router`が使われています。

```jsx
function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/profile" element={<Profile />} />
      </Routes>
    </BrowserRouter>
  );
}
```
このように、`BrowserRouter` を使えば `history.pushState()` を意識することなく、**「画面とURLの1対1の対応」** を自然に実現できます。

## SPAの初期表示の課題
ただし`SPA`にはもう１つ課題があります。
それは、**<font color='red'>初回表示時にJavaScriptの読み込みと実行が完了するまで画面が表示されない</font>** という点です。

この問題に対処する技術が、 **SSR（サーバーサイドレンダリング）** です。
代表的なフレームワークである `Next.js` は、`React` をベースにしつつ `SSR` に対応しており、初期表示の高速化や、SEOの改善に役立ちます。


## まとめ
今回は、`SPA` や `fetch` について「なぜ使われているのか」「どんなメリットがあるのか」が少しずつ理解できました。
今後、現在学習中の `React` やこれから学習する `Next.js` で、画面遷移やデータ取得を扱うときは、こうした背景を意識しながら使いこなしていきたいと思います。