対象読者
- Reactの基本を修めている方
- 通信回線が弱いユーザーにも高速に表示できるサイトを作りたいエンジニア
- WebブラウザとNode.jsという異なるランタイムをそれぞれキャッチアップするのが辛くなってきたエンジニア
前提環境
筆者の検証環境は以下の通りです。
- macOS Ventura 13.0.1
- Node.js 18.12.1
- NPM 8.19.2
- Remix 1.9.0
Nested Routesでページ内の一部分だけを別のファイルで定義する
前回はHacker Newsの最新20件を読めるアプリケーションを途中まで作り、メニューが表示できるようになりました。図1のように、idが sidebar
になっているメニュー部分と、コンテンツを表示する予定の <main>
要素で構成されています。
メニューを作ったので、次はメニューの項目をクリックしたときに、 <main>
要素にある本文に記事を表示します。具体的には、 /top20/xxxxxx
のようなURLへアクセスしたときに、本文が表示されると嬉しいです。
こういった挙動を作るときに役立つのが、Nested Routes(ネステッドルーツ)と呼ばれる機能です。ルート(ページ)の定義をネスト(入れ子)にすることで、画面遷移の際にページ内の一部分だけを更新することができます。
1つのページのレイアウトを複数のファイルで構成する
実際の挙動を見たほうが早いので、手を動かしてみましょう。図1の例では <main>
要素の中に <div>
要素を仮置きしていましたが、これを <Outlet />
という要素に置き換えます(リスト1)。 Outlet
は "@remix-run/react"
のインポート文を追記して呼び出します。
import { useLoaderData, Link, Outlet } from "@remix-run/react"; // 中略 <main> <Outlet /> </main>
この <Outlet />
は、いわゆるプレースホルダーです。アクセスするURLのパスに応じて、別のファイルで定義したコンポーネントに差し変わります。といっても、どんなパスでも差し替えられるわけではありません。 <Outlet />
が設置されたファイルと同名のフォルダ内のファイル が <Outlet />
に表示されうるものになります。
テキストだけだとわかりづらいので、実際に簡単な例から表示してみましょう。図2のように、 app/routes
フォルダの直下に、 top20
フォルダを作成し、さらにその下に app/routes/top20/index.jsx
を作成します。
一見すると app/routes/top20.jsx
と同じページを別の表現で作成しただけに見えますが、Remixでは異なる役割を持っており、どちらも必要なので残しておいてください。
続いて、 app/routes/top20/index.jsx
の中身はリスト2のように実装します。
import stylesUrl from '~/style/article.css'; export const links = () => { return [{ rel: "stylesheet", href: stylesUrl }]; }; export default function Top20IndexRoute() { return ( <article> <p>ここに記事が表示されます。</p> <p>左のメニューから記事を選択してください。</p> </article> ) }
特段複雑なことをしない、静的な表示です。
では、この状態で http://localhost:3000/top20
を確認してみましょう(図3)。
<Outlet />
を配置した場所に、リスト2で実装した app/routes/top20/index.jsx
の内容が表示されました。routeの中にrouteを表示する仕組みということで、Nested Routesと呼ばれています。 app/routes/top20.jsx
と app/routes/top20/index.jsx
は、どちらか一方だけが実装されている場合は同じパス(/top20
)を表現するための同じ役割のファイルです。
しかし、同時に実装した場合には、 app/routes/top20.jsx
が外側のレイアウト部分を担当し、 app/routes/top20/index.jsx
がコンテンツ部分を担当するように、役割が変わるのです。
この状態では、Nested Routesの真価はまだ発揮されていません。というのも、 app/routes/top20.jsx
という外側のレイアウトを司るファイルは app/routes/top20/
フォルダ配下のすべてのファイルに対して適用されるのです。 index.jsx
でも、それ以外のファイルでも、同じように app/routes/top20.jsx
が外側のレイアウトとして表示され続けることに真価があります。つまり、 /top20/xxxxxx
のようなパスを表示するときにも、サイドメニューを表示させ続けることができます。