ドキュメントを読んだのでRemixのRouting(v2)を整理する
Remixのドキュメントに従って実例を交えながらRoute File Naming (v2)の解説を行います。
前提として、remix.config.jsでv2_routeConvention: true
を設定することを忘れないでください。
/** @type {import('@remix-run/dev').AppConfig} */
module.exports = {
future: {
v2_routeConvention: true,
},
};
ルートレイアウト(Root Route)
app/
├── routes/
└── root.tsx ← こいつのこと
Remixは、app/root.tsx
にアプリケーション全体の共通処理や共通レイアウトを定義することができます。
例えば、ヘッダーやフッターといった共通レイアウトや、メタ情報を設定するためのHTMLヘッダーなどを記述することができます。
ただし、一部のページのみ対象から除外することが出来ない点に注意して実装してください。
以下の例はメタ情報とヘッダーフッターを設定する例です。
<Outlet />は子コンポーネントになります。childrenみたいなものだと考えてもらえれば問題ないと思います。
import { Outlet } from "@remix-run/react";
export default function App() {
return (
<html lang="ja">
<head>
{/* メタ情報などの設定 */}
</head>
<body>
{/* 共通のヘッダーコンポーネント */}
<Header />
{/* ページ固有のコンテンツ */}
<Outlet />
{/* 共通のフッターコンポーネント */}
<Footer />
</body>
</html>
);
}
基本のルーティング(Basic Routes)
Remixでは、app/routes配下にページを配置したファイルがそのままアプリケーションのURLになります。
例えばapp/routes/home.tsx
にファイルを配置すると、/home
のURLパスでhome.tsx
のコンポーネントにアクセスできるようになります。
app/ URLパス
├── routes/
│ ├── _index.tsx /
│ ├── home.tsx /home
└── root.tsx
ドット分割(Dot Delimiters)
Remix Routing(v2)では、ファイル名に.
をつけることでURLの/
を生成します。
例えばroutes/home.contents.tsx
は、アプリケーション上ではURLパス/home/contents
でアクセスすることができます。
Remix Routing(v2)環境においては、routes/
内にディレクトリを置くことはありません。
routes/setting/notification.tsx
のような構成はしないことを注意してください。
app/ URLパス
├── routes/
│ ├── _index.tsx /
│ ├── home.tsx /home
│ ├── home.contents.tsx /home/contents
└── root.tsx
動的セグメント(Dynamic Segments)
Remixで動的セグメントを利用する場合$
を利用します。
routes/user.$id.tsx
は、URLパス/user/11111
や、/user/12121
でアクセスすることができます。
app/ URLパス
├── routes/
│ ├── _index.tsx /
│ ├── home.tsx /home
│ ├── home.contents.tsx /home/contents
│ ├── user.$id.tsx /user/{任意の値}
└── root.tsx
動的セグメントで設定されたURLパラメータは、ローダーやアクションで取得することができます。次の例は、動的セグメントで指定されたidを使用して、対応するユーザー情報を取得するためのローダーの例です。
export function loader({ params }: LoaderArgs) {
const userId = params.id
return getUser(userId);
}
ネストを含むルーティング(Nested Routes)
Remixでは、ドットで分割されたファイル名の前の部分が一致するファイル同士は親子関係が形成されます。
例えば、home.contents.tsx
はhome.tsx
の子要素になります。
このような場合、Remixでは子要素は親要素の<Outlet />内でレンダリングされます。そのため、子要素は親要素のレイアウトを引き継ぐことになります。
この時、親要素に<Outlet />
の配置を忘れると子要素がレンダリングされないことに注意してください。
app/ URLパス レイアウト
├── routes/
│ ├── _index.tsx / root.tsx
│ ├── home.tsx /home root.tsx
│ ├── home.contents.tsx /home/contents home.tsx
│ ├── user.$id.tsx /user/{任意の値} root.tsx
└── root.tsx
親コンポーネントの実装例
const Home = () => {
/* homeの共通処理 */
return (
{/* homeの共通レイアウト */}
<Outlet />
);
};
export default Home;
この時、URLパス/home
でhome.tsx
に直接アクセスするとhome
の<Outlet />
部分がレンダリングされません。
しかし、インデックスルートファイル(hoge._index.tsx
等)を配置することで、ユーザーが親要素に直接アクセスした際、<Outlet />
が空のままページがレンダリングされることを防ぐことができます。
今回の場合は、home._index.tsx
ファイルを配置しています。
インデックスルートファイルも、親要素のレイアウトを引き継ぎ、親要素の<Outlet />
内でレンダリングされます。
app/ URLパス レイアウト
├── routes/
│ ├── _index.tsx / root.tsx
│ ├── home.tsx root.tsx
│ ├── home._index.tsx /home home.tsx
│ ├── home.contents.tsx /home/contents home.tsx
│ ├── user.$id.tsx /user/{任意の値} root.tsx
└── root.tsx
レイアウトが反映されない入れ子(Nested URLs without Layout Nesting)
子要素ファイル名の親セグメントの末尾に_
をつけることで、URLを入れ子にしつつ、親要素のレイアウトは引き継がないことができます。
app/ URLパス レイアウト
├── routes/
│ ├── _index.tsx / root.tsx
│ ├── home.tsx root.tsx
│ ├── home._index.tsx /home home.tsx
│ ├── home.contents.tsx /home/contents home.tsx
│ ├── home_.mine.tsx /home/mine root.tsx
│ ├── user.$id.tsx /user/{任意の値} root.tsx
└── root.tsx
追加したhome_.mine.tsx
は、URL上ではhomeの配下に入りますが、レイアウトはroot.tsx
が反映されています。
パスレスルート(Nested Layouts without Nested URLs)
子要素親セグメントの先頭に_
をつけることで、URLは独立させたままレイアウトを共通にすることができます。
app/ URLパス レイアウト
├── routes/
│ ├── _index.tsx / root.tsx
│ ├── home.tsx root.tsx
│ ├── home._index.tsx /home home.tsx
│ ├── home.contents.tsx /home/contents home.tsx
│ ├── home_.mine.tsx /home/mine root.tsx
│ ├── _home.auth.tsx /auth home.tsx
│ ├── user.$id.tsx /user/{任意の値} root.tsx
└── root.tsx
追加された_home.auth.tsx
は、home.tsx
のレイアウトを引き継いでいるが、URLパスにhomeが含まれいないことがわかると思います。
親セグメントの先頭に_
をつけることで、URLを隠すことができる。といった考え方が分かりやすいかもしれません。
まとめ
Remixのルーティングは
- ネストルーティング
- 動的セグメント
- レイアウトを含まないネスト
- パスレスルート
以上の4つを理解することで、基本的なルーティングは実現することができると思います。
この場では紹介しきっていないテクニックも存在しているため、今回紹介したテクニックのみで実現できない実装があれば、公式のドキュメントを眺めてみてください。
Discussion
Remix v2のRouting、わかりやすくて参考になりました!
1点確認なのですが、ディレクトリ構造の例で紹介されている
user.$id.tsx /home/{任意の値} root.tsx
の部分は
user.$id.tsx /user/{任意の値} root.tsx
ではないでしょか?
user.$id.tsx /user/{任意の値} root.tsx
が正しいです!ご指摘ありがとうございます!