対象読者
- JavaScriptとWeb開発の基礎に理解がある方
- Reactに興味/関心があり、これから学び始める方
前提環境
筆者の検証環境は以下の通りです。
- macOS Sierra 10.12
- Node.js v8.9.3/npm 5.5.1
- React 16.1.1
- react-router-dom 4.2.2
画面遷移とReactとURL
GUIアプリケーションが多くの機能を持つために欠かすことができない機能のひとつとして、画面遷移があります。図1はページを2つ持つWebサイトの例です。
画面遷移を用いることによって、機能の役割ごとにページを分けることができます。すべての機能が1つのページに詰め込まれているよりも、機能がほどよく絞られた画面が、利用者にとって心地よいものになることは皆さんもよく知るところでしょう。
Reactと画面遷移
従来のWebアプリケーションにおいて、最もポピュラーな画面遷移の方法は、アンカータグ(aタグ)を用いてリンクを作り、それをクリックしてもらうことで別のページ、つまり別のHTMLファイルを表示してもらうことでした。
しかし、本連載で扱っているReactは「シングル」ページアプリケーションを作るためのライブラリです。シングルページアプリケーションは、最初に開いたHTMLファイルの中でアプリケーションを動かし続けることで、見た目上のパフォーマンスを向上させることに価値を置いた手法ですから、別のHTMLファイルへ頻繁に移動してしまっては本末転倒といえるでしょう。
では、Reactを用いたシングルページアプリケーションにおいて、画面遷移とは何を指すのでしょうか。
細かいことを抜きにして説明してしまえば、単なるコンポーネントの差し替えで十分です。図1の例でいうところのメニュー部分の選択状態をstateで管理している場合、次の処理が書けます。
render() { // メニューの選択状態 const currentPage = this.state.currentPage; // (1) // メイン部分のコンポーネントの入れ物 let Content = null; // デフォルトでは何も表示しない switch (currentPage) { case "記事を見る": // 記事を見るページのコンポーネント Content = (() => <Article id="001" />); break; case "お問い合わせ": // お問い合わせページのコンポーネント Content = (() => <Contact />); break; } return ( <div> <Header /> <Menu /> <Content /> {/* (2) */} </div> ); }
メニュー側でcurrentPageに対してsetStateを行うことで、(1)が変化し、(2)に配置されるコンポーネントが切り替わります。ユーザーから見れば、メニューの選択状態に応じてコンテンツが変わっているわけですから、これも立派な画面遷移です。
ReactとURL
コンポーネントの差し替えで画面遷移らしきことができたので、めでたしめでたし。というわけには、残念ながらなりません。最初に開いたHTML(多くの場合はindex.htmlですね)の中でコンポーネントを差し替えているだけなので、URLはそこから変わっていないのです(図2)。
アドレスバーのURLを気にしているユーザーなんて、開発者や一部のヘビーユーザーしかいないから、URLが変わらないなんて些細な問題だ、と思った方もおられると思います。侮るなかれ、この挙動は次のような問題を引き起こすのです。
- 進む・戻るボタンが効かない
- 特定のコンテンツに対するブックマークができない
どちらも、一般的なインターネットユーザーがネットサーフィンをする中で、頻繁に行う操作です。これでユーザビリティの観点から無視できない挙動であることがお分かりいただけたでしょうか。ページの見た目に合わせてURLが切り替えられるようになれば、この問題を解決できそうです。
実は、ちょうどいい機能がHTML5で追加されています。History APIです。本記事の本筋から外れてしまうので詳しくは説明しませんが、次のような関数が用意されています。
window.history.pushState(null, null, "/articles/001");
この例を実行すると、次のことが起こります。
- アドレスバーのURLが「http(s)://ドメイン名/articles/001」になる
- 閲覧履歴が1つ進んだことになり、ブラウザの戻るボタンで直前のURLに戻れる
この挙動の興味深いところは、アドレスバーのURLが変わっても、表示しているHTMLファイルを変えるわけではないというところです。シングルページアプリケーションにはうってつけのAPIですね。Reactでstateを使ってコンポーネントを差し替えた際に、同時にhistory.pushStateで適切なURLを指定すれば、あたかも違うHTMLファイルを開いたかのように見える挙動をしてくれそうです。
役者は出そろいました。コンポーネントの差し替えによる画面遷移と、History APIによるアドレスバー操作。この2つを組み合わせれば、ユーザビリティを損なわない画面遷移が実装できそうです。
ただ、コンポーネントの状態とURLの状態を同期させながら管理するのは一手間かかりそうです。できたら、何かのライブラリを使いたいところですね。
お待たせしました。これらの課題を解決するためのライブラリが、今回のテーマである「React Router」です。