【React × TypeScript】react-router-dom 基本編
概要
勉強のためにReactとTypeScriptを使用したアプリを開発中です。その過程でreact-router-dom v6について調べたことをまとめています。
まだまだ勉強中なので、間違っている部分や誤解を招きやすい部分があれば教えていただけると嬉しいです。
環境構築
まずはインストールしましょう。
npm install react-router-dom @types/react-router-dom
TypeScriptのバージョンや環境によって@types/react-router-dom
のインストールは不要の場合もあります。
ルーティング
ページ上部に常時ヘッダーを表示させながら、ページ下部の表示のみをクリックするメニューによって変えるウェブサイト例に説明していきます。
import { BrowserRouter as Router, Route, Routes, Outlet } from "react-router-dom"
function App() {
return (
<Router>
<Routes>
<Route
element={
<div>
<h1>Layout</h1>
<Outlet />
</div>
}
>
<Route path="/" element={<h2>Home</h2>} />
<Route path="/about" element={<h2>About</h2>} />
</Route>
</Routes>
</Router>
)
}
export default App
基本、Router
> Routes
> Route
がワンセットでRouteタグで詳しい設定を行います。モジュールをインポートするのも忘れないようにしましょう。
ここでは、一番上のRoute
が親となって、2つの子Routeを囲んでいます。このようにすると、親Route(Layout
)は常に表示され、アクセスするパスによってOutlet部分で表示される子RouteがHome
になったりAbout
になったりします。/
にアクセスする場合はHomeが呼び出され、/about
にアクセスするとAboutが呼びされる、ということです。
path
:URLを設定する
element
:呼び出すコンポーネントを指定する
一番外側のRouter
はrootファイルに書く方法もあります。
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import { BrowserRouter as Router } from 'react-router-dom'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<Router>
<App />
</Router>
</React.StrictMode>,
)
LayoutとOutlet
先ほどのLayoutとOutletについて、もう少し見ていきます。
上の例ではコンポーネントファイルを使わないコードを紹介しましたが、実際によく見かけるのは下のようなコードだと思います。
import { BrowserRouter as Router, Route, Routes } from "react-router-dom"
import Layout from "./Layout"
import Home from "./home"
import About from "./About"
function App() {
return (
<Router>
<Routes>
<Route path='/' element={<Layout />}>
<Route index element={<Home />} />
<Route path="/about" element={<About />} />
</Route>
</Routes>
</Router>
)
}
export default App
import { Outlet } from "react-router-dom"
import Header from "./Header"
const Layout = () => {
return (
<>
<Header />
<Outlet />
</>
)
}
export default Layout
const Header = () => {
return (
<h2>Header</h2>
)
}
export default Header
図にするとこんな感じです
ここでは、Layout
, Header
, Home
, About
のコンポーネントファイルを作成しました。
/
にアクセスするとLayout
コンポーネントが表示され、その中にはHeader
とOutletが入っています。そうすることで、いつでもHeader
コンポーネントとOutletが表示されます。先ほども説明した通り、Outletは親Routeが囲っている子Routeをパスに合わせて表示するものです。これで、いつでもHeader
を表示しながらアクセスするパスによって下部の表示だけを変えられるようになりました。
Link
今のままでは、URLを直接変えないと表示が変わらないので画面上にもリンクを設置していきます。
import { Link } from "react-router-dom"
const Header = () => {
return (
<>
<Link to='/'>Home</Link>
<Link to='/about'>About</Link>
</>
)
}
export default Header
このときに使うのがLinkです。Link要素は、クリックすることで指定したコンポーネントの表示をしてa href
のような働きをします。ただ、aタグとは違い、ページのリロードが起こらないので不要なページのリロードやを避け、stateの状態を保持してくれます。
以上で、ヘッダーは常に上部に置いたまま、その下の部分のみ表示を変更する仕様が完成です。
SwitchとRoutes
react-router-domについて検索するとSwitch
を使用した例をよく見かけますが、うまく動きませんでした。v5ではSwitchを
使用していたようですが、v6ではRoutes
を使うのが推奨されています。
NotFoundページの作成
<Route path="*" element={<NotFound />} />
このコードで、存在しないパスへのアクセスは全てNotFoundページに遷移されるようになります。
参考
Discussion