※この記事は「エムティーアイ Blog Summer 2025」の 8/20 分の記事です。
はじめに
こんにちは。スマートコンテンツ事業部の高木です。
今回は、私が最近知って驚いた「React Router における共通レイアウトの扱いについて」についてご紹介します。
共通レイアウトとは?
フロントエンド開発では、headerやfooterなど、どの画面でも共通して表示される部分(共通レイアウト)がありますよね。
私はこれまでReactでUIを実装する際、headerやfooterなどの共通レイアウトをApp.jsに直接インポートしていました。
そうするとルーティングの記述とレイアウトの記述が混在してしまい、コードが読みづらくなるという問題がありました。
そこで、Next.jsの機能にあるsrc/app/layout.tsxのような仕組みが実現できないか調べてみたところ、
Reactでルーティングを実装するために利用していた、React RouterのOutletというコンポーネントで共通レイアウトを扱えることを知りました。
React RouterのOutlet
ドキュメントを見てみると、
Renders the matching child route of a parent route or nothing if no child route matches.
日本語訳:親ルートの中でマッチする子ルートを表示します。マッチする子ルートがない場合は何も表示しません。
マッチする子ルートのイメージがつかなかったので、実際にサンプルコードを使って試してみます。
SomeParent.js
import { Outlet } from "react-router-dom"; export default function SomeParent() { return ( <div> <h1>Parent Content</h1> <Outlet /> </div> ); }
Child.js
export default function Child() { return <div>Child Content</div>; }
App.js
import { BrowserRouter, Routes, Route } from "react-router-dom"; import SomeParent from "./SomeParent"; import Child from "./Child"; export default function App() { return ( <BrowserRouter> <Routes> <Route element={<SomeParent />}> <Route path="/child" element={<Child />} /> </Route> </Routes> </BrowserRouter> ); }
実際に動かしてみると、
/にアクセスすると、親ルート(SomeParent.js)の内容のみが表示されています。

/childにアクセスすると、親ルート(SomeParent.js)の内容に加えて、子ルート(Child.js)の内容も表示されています。

つまり・・・
親ルートの中でマッチする子ルート=ルーティングで階層構造になっている部分を指すようです。
共通レイアウトを実装してみる
それでは実際に、以下のような共通レイアウトを作ってみます。

App.js
import { BrowserRouter, Routes, Route } from "react-router-dom"; import SomeParent from "./SomeParent"; import Layout from "./Layout"; export default function App() { return ( <BrowserRouter> <Routes> <Route element={<Layout />}> <Route path="/" element={<SomeParent />} /> </Route> </Routes> </BrowserRouter> ); }
Layout.js
import Header from "./Header"; import Sidebar from "./Sidebar"; import { Outlet } from "react-router-dom"; import "./layout.css"; const Layout = () => { return ( <div className="layout-root"> <Header /> <div className="layout-content"> <Sidebar /> <main className="main"> <Outlet /> </main> </div> </div> ); }; export default Layout;
実際に動かしてみると、

App.jsで記述したルーティングにより、Layoutの下の階層にあるページ全てに共通レイアウトが適用されます。
Outletを使ってみて感じたこと
メリット
App.jsがルーティングの記述だけになり、コードがすっきりして見やすくなる
デメリット
- 特になし(現時点では特にデメリットは感じていません)
感想
これまではApp.jsに共通レイアウトを直接書いていたため、コードが煩雑になりがちでした。
Outletを使うことで、レイアウトとルーティングを分離でき、コードが読みやすい良い構成にできると感じました。
今後も積極的にOutletを活用していきたいと思います!