FFFT

主にwebプロダクト開発に関連する話をつらつらと

react-routerを使ったアプリ内遷移の方法 / historyはどう取得するのが良いか

f:id:keyama4:20200723123912p:plain

Reactで作ったWebアプリケーションではルーティングの管理や開発に、react-routerを使用することが一般的かと思います。
今回は、react-routerを使ったWebアプリケーションでのアプリ内遷移の方法をまとめます。

react-routerを使ったアプリ内遷移方法

まず前提として、Reactで作成するWebアプリケーションはSPAとなります。(少なくともReactで動的に変更される箇所は)
SPAでのアプリ内遷移はサーバへのアクセスが不要で、クライアントサイドですべて完結するのが特徴です。
爆速の遷移変更のUXを提供してくれます。
内部的には設定されているルーティングに応じて、表示させるビューを切り替えているイメージです。
SSR(サーバサイドレンダリング)のアプリケーションでは、画面の遷移にサーバとの通信が発生します。
ブラウザからURLを直叩きしたり、hrefで遷移させたりするやつですね。
React製のアプリケーションでも、同様の遷移方法が可能ですが、ページを構成するすべてのコンテンツのレンダリングからとなるためSPAの初期化からやり直しになり、SPAの旨味がなくなります。

React(react-router)でのアプリ内遷移方法は大きく下記2つになります。

それぞれ見ていきましょう。

Linkコンポーネントを使った遷移

Linkコンポーネントを使った遷移は、リンククリックのイベントを使って遷移を実現します。
aタグを使った遷移の利用シーンと同様です。aタグでの遷移のアプリ内遷移用の用途として認識しておくと良いと思います。(前述しましたが、アプリ内遷移にaタグを使うと遷移のパフォーマンスが悪い且つSPAの旨味なし)
Linkコンポーネントはtoのpropsに遷移先のパスを指定するのが、最もベーシックな使い方です。

例えば、下記のようなルーティングの設定があった場合。

    <BrowserRouter>
        <Switch>
            <Route path="/home" component={HomeComponent}/>
            <Route path="/page1" component={Page1Component}/>
            <Route path="/page2" component={Page2Component}/>
            <Route path="/page3/hoge" component={Page3HogeComponent}/>
        </Switch>
    </BrowserRouter>

HomeComponentからPage1ComponentにLinkで遷移させようとするとHomeComponentに下記を追加するイメージです。

...
<Link to="/page1">ページ1へ</Link>
...

Linkコンポーネントは上記のようにaタグのhrefと類似のベース機能を提供していますが、他にもパス以外にクエリストリングやハッシュ、locationに紐づけた状態を管理できたりします。

<Link to={{pathname: "/page1", search: "?param1=123", hash: "#sample", state: { fromHome: true }}}>ページ1へ</Link>

個人的にはsearchもhashもtoにそのまま含めた方がわかりやすかったりするシーンがほとんどなのでほとんど使わないです。
stateも実際に公開しているアプリケーションでは、まだ使ってないです。contextで状態管理させる方がわかりやすい。

詳細は公式ページをご覧ください。 reactrouter.com

historyを使った遷移

前述のLinkコンポーネントはユーザーのリンククリックのアクションのタイミングでしたが、APIのレスポンスの結果で画面を切り替えたいなどの動的な遷移を実現させたいシーンがあるかと思います。
そういったシーンでは、historyを使用します。
historyは、URLと状態を含むlocationを使用してアプリケーションの履歴を追跡するためのAPIを提供します。 名前のとおり、履歴まわりに主な役割がありそうな感じですが、パスの変更もこのライブラリを使用します。ちなみにreact-routerはhistoryへの依存性がめちゃくちゃ高い。
遷移方法は、主に5つありますがまずはpushを使えれば良いかと思います。
詳細は下記のAPIリファレンスをご覧ください。
github.com

コンポーネントからhistoryをどう取得すれば良いのか

historyオブジェクトを使えば、動的なアプリ内遷移の実現が可能ということはわかりましたが各コンポーネントからどう取得するのが良いのでしょうか。
いくつかやり方がありますが、最もカンタンなのはreact-routerのhooksを利用するやり方です。
useHistoryを使うと、Routerコンポーネントで管理されているhistoryオブジェクトを渡してくれます。

...
export const SampleComponent: FC<Props> = () => {
    const history = useHistory();
    history.push('/page1');
...

hooksが提供される以前は、RouteChildrenPropsから取得するやり方をよく記事で見ていました。
しかし、このやり方はRouteコンポーネントのpropsとして渡されていないコンポーネントからは取得できなかったり、使い勝手が悪かった。
そこで、アプリケーションの初期化タイミングでhistoryオブジェクトを生成してRouterコンポーネントに渡し、グローバルで管理してどこからでも利用できるように実装することをやってたんですが、useHistoryはそれを全部やってくれる。ありがたい。
また、他のhooks(useParams, useLocation)を使えば、RouteChildrenPropsから引っ張ってこなくてはいけなかった値をカンタンに取得・利用することができます。
hooks便利。
useHistoryや他のhooksの詳細情報は下記をご覧ください。

reactrouter.com