通常のMVCで作られたサーバーサイドWebアプリケーションで、ルーティングとは何かと問われたら、リクエストされたURLに対して、そのURLに紐づくページをアプリケーションサーバーが、クライアントに返す事 という答えになるかと思いますが、SPAでのルーティングは、解釈が異なります。
SPAは、サーバーへの初回リクエストに対して、そのURLに関わらず、アプリ全体が記述されたJSのコードとアセットファイルがごそっと返されます。以降、アプリ内部でのページ遷移は、アプリが動的にDOMを書き換えることにより、移動してるように見せてるだけである点が、大きな特徴です。これは、ブラウザのアドレスバーのURLが書き換わっても、その処理もブラウザの中で完結しており、実際にサーバーへリクエストを飛ばすことは原則的に無いという事です。
では、サーバーにリクエストを送る事なく、ルーティングを実現するために、どうしてるか?これは、History APIという技術が使われています。HTML5から導入された__pushState()__ と__replaceState()__ で、ブラウザのセッション履歴に任意のURLを追加したり、特定の履歴を書き換えたりしながら、JSで履歴のURLを制御することを可能にしています。
詳しくは、MDNのドキュメントへ。(時間のある時に一読しておくことをお奨めします)
以上の事から、SPAのルーティングとは?という問いに対しては、以下の解釈が妥当になるかと思います。
SPAにおけるルーティングとは、『DOMの動的な書き換えによってページ遷移を擬似的に実現するとともに、ブラウザのセッション履歴をそれに同期させる事』
...と言えます。
SPAでのルーティングの適用単位は、コンポーネントです。LaravelやRailsだと、ひとつのURLに対応するのはControllerで、それがviewを経由して、ページ全体を描画するが、Reactは、ルートのコンポーネントから階層を下り、ここから先はこのコンポーネントがマウントされる、このパスの時には別のコンポーネントがマウントされるといったように、コンポーネントそのものがルーティングとなります。
その他、開発時に考慮しなければいけない前提として、以下が挙げられます。
サーバーへリクエストを投げないということは...
① サーバー側から、クライアントがどんなページを見てるか、どう移動したかは分からない。これはアクセス解析時にネックとなる。(これは、ルーティングが実行されてURLが書き換わる際に、Effect HookでGAにリクエストを発行する処理を挟むことで対処できる)
② HTTPステータスコードを返せない。
③ pushStateを使ったルーティングでは、 履歴が変わって、新しいページがレンダリングされても、スクロール位置は遷移前のままとなる。(サーバーサイドであれば、ページ遷移すれば、毎回トップ位置から表示される)この場合、以下のようなコードを書いて対処する必要がある。
const {hash, pathname} = useLocation();
const {action} = useHistory();
useEffect(()=> {
if (!hash || action !== 'POP') {
window.scrollTop(0,0);
}
}, [action, hash, pathname])