ファイルベースルーティングの命名規則
Expo Routerの強力な機能の多くは、appディレクトリ内のファイルやフォルダの命名規則に基づいています。本題であるレイアウトの仕組みを理解する上で、これらの命名規則(ファイル記法)を把握しておくことが重要です。ここでは主要なものをいくつか紹介します。詳細については、公式ドキュメントのExpo Router notationも参照してください。
静的ルート (Static Routes)
特別な記号を含まないファイル名やディレクトリ名は、そのままURLのパスに対応します。例えば app/home.jsは/homeというURLでアクセスできます。
動的セグメント (Dynamic Segments)
ファイル名やディレクトリ名に角括弧[]を使用すると、その部分が動的なパラメータになります。
app/users/[id].jsは、/users/1や/users/nakagawaのようなURLにマッチします。idの部分はコンポーネント内でuseLocalSearchParamsフックを使って取得できます。
グループルート (Groups)
ディレクトリ名を丸括弧()で囲むと、「グループルート」になります。これはURLのパス構造には影響を与えません。主な目的は、関連するルート群を整理したり、特定のルート群に共通のレイアウトを適用したりすることです。
app/(tabs)/home.jsは/homeというURLでアクセスできます。(tabs)はURLに含まれませんが、このグループ内のルート群に対してタブベースのレイアウトを適用する、といった使い方ができます。
同様にapp/(stack)/settings.jsは/settingsとなります。
デフォルトルート (index.js)
index.jsファイルは、そのディレクトリのデフォルトルートとして機能します。例えば app/index.jsはアプリのルート/に対応します。
レイアウトルート (_layout.js)
アンダースコアで始まる_layout.jsファイルは、特別な役割を持ちます。これはページコンポーネントではなく、同じディレクトリ内(またはそのサブディレクトリ)のルート群に対する共通の外枠、つまり「レイアウト」を定義するためのファイルです。例えば、ヘッダー、フッター、ナビゲーションバーなどをここに記述します。
app/_layout.jsはアプリ全体のルートレイアウトを定義します。app/(tabs)/_layout.jsは(tabs)グループ内のルート群(タブ画面)のレイアウトを定義します。
この_layout.jsこそが、本記事のメイントピックです。次のセクションで詳しく解説します。
特殊ファイル (+ 記号)
ファイル名の先頭にプラス記号 + が付くものは、Expo Routerによって特別な意味を持つファイルとして扱われることがあります。
これらのファイル記法を組み合わせることで、複雑なナビゲーション構造も宣言的かつ直感的に構築できます。特に「グループルート」と「レイアウトルート (_layout.js)」の概念は、この後の解説を理解する上で鍵となります。
レイアウトルートの役割と振る舞い
ファイル記法のセクションで触れたように、_layout.jsファイルはExpo Routerにおけるレイアウトを表現するためのものです。このファイルを用いることで、特定のディレクトリ(セグメント)とその配下のすべての画面(ルート)に対し、共通のUIコンポーネント、ナビゲーション構造、その他のロジックを一元的に提供できます。
レイアウトコンポーネントの最も基本的な機能は、子となる画面コンポーネントを描画することです。これは expo-routerからインポート可能なSlotコンポーネントを使用して実現します。<Slot />は、現在アクティブな子ルートのコンテンツに置き換わるプレースホルダーとして機能します。_layout.jsが何も返さないか、Slotをレンダリングしない場合、その子ルートは表示されません(図3)。
_layout.jsが具体的にどんな場面で役立つのか、主要な使用例を見ていきましょう。
アプリ全体の共通レイアウト (app/_layout.js)
最も基本的かつ広範囲に影響するのが、appディレクトリ直下に配置するapp/_layout.jsです。
これはアプリケーション全体のグローバルなレイアウトを定義し、すべての画面に適用されます。レイアウトの定義がない場合はapp/index.jsが最初に読み込まれますが、app/_layout.jsが存在する場合はこちらが優先され、アプリのエントリーポイントとなります。
そのため、主な用途として以下が挙げられます。
- アプリケーション全体に共通のテーマ(例: React Contextを用いたダークモード対応など)を適用する。
- カスタムフォントを読み込み、アプリ全体で利用できるようにする。
- プッシュ通知の受信設定や初期化処理を行う。
- ユーザーの認証状態を監視し、状態に応じて表示する画面群(例: ログインユーザー向け画面とゲスト向け画面)を動的に切り替えるナビゲーションロジックを実装する。
最もシンプルなapp/_layout.jsは、単にSlotコンポーネントを返すだけの構成です(リスト1)。
import { Slot } from 'expo-router';
export default function RootLayout() {
// アプリ全体に適用したい初期化処理などはここで行う
return <Slot />;
}
上記の例では、<Slot />コンポーネントを返却しているだけですが、この<Slot />部分が、app/index.jsやapp/home.jsといった具体的な画面コンポーネントの描画結果に置き換えられます。もし<Slot />を別のViewコンポーネントや他のカスタムコンポーネントで囲むと、それが全画面共通のラッパー(親)コンポーネントとして機能します。
例えば、全画面に共通の背景色や余白(パディング)を設定したい場合は、次のようにします。
import { Slot } from 'expo-router';
import { View, StyleSheet } from 'react-native';
export default function RootLayout() {
return (
<View style={styles.container}>
<Slot />
</View>
);
}
// (略)
このように、app/_layout.jsはアプリケーション全体のルック&フィールや、グローバルな初期化処理などを定義する上で非常に重要な役割を担います。開発者はこのファイルを活用することで、アプリ全体に一貫した体験を提供しやすくなります。
以降に登場するレイアウトでは、ナビゲーションというコンポーネントを配置しますが、これらも内部的には「 <Slot />をどんなルールで切り替えるか」という処理を行っているだけであることを念頭に置いておくとよいでしょう。
