対象読者
- 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 のようなパスを表示するときにも、サイドメニューを表示させ続けることができます。
