いまのことりずかんは、どれだけ機能を足してもページが1枚です。鳥の名前を押しても、詳しい説明を出す場所がありません。
この回で、URLでページを分けます。
Reactは何もしないと1ページ
index.htmlは1つだけで、その中身をReactが書きかえている——最初の回で見たとおりです。だからURLは変わらないままです。
「ページを分けたように見せる」には、URLとコンポーネントを対応づける道具が要ります。それがルーティングのライブラリで、定番がReact Routerです。
npm install --save-exact react-router-dom3つの部品でできている
React Routerで覚えるのは、まず3つだけです。
| 部品 | 役目 |
|---|---|
<BrowserRouter> | アプリ全体を包む。「ここからURLを見ます」の宣言 |
<Routes> / <Route> | URLとコンポーネントの対応表 |
<Link> | ページ内リンク。<a>の代わりに使う |
①全体を包む
import { BrowserRouter } from 'react-router-dom'
createRoot(document.getElementById('root')).render(
<StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</StrictMode>,
)②対応表を書く
App.jsxは対応表だけになります。中身はページごとのコンポーネントに移します。
import { Route, Routes } from 'react-router-dom'
import BirdListPage from './pages/BirdListPage.jsx'
import BirdDetailPage from './pages/BirdDetailPage.jsx'
import NotFoundPage from './pages/NotFoundPage.jsx'
function App() {
return (
<Routes>
<Route path="/" element={<BirdListPage />} />
<Route path="/birds/:id" element={<BirdDetailPage />} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
)
}読み方はこうです。
path="/"——トップ。一覧を出すpath="/birds/:id"——:idの部分は何が来てもいい(/birds/1でも/birds/8でも当たる)path="*"——どれにも当たらなかったとき。404ページ
elementにはJSXを渡します(<BirdListPage />のようにタグの形)。関数名だけを渡すのではない点に注意してください。
③<Link>でつなぐ
import { Link } from 'react-router-dom'
<Link to={`/birds/${bird.id}`}>{name}</Link>hrefではなくtoです。
URLの一部を受け取る:useParams
/birds/1の1を受け取るのがuseParamsです。
import { useParams } from 'react-router-dom'
function BirdDetailPage() {
const { id } = useParams() // "1"(文字列)
…
}{ id }の名前は、<Route path="/birds/:id">の:idと同じ名前にします。ここがそろっていないとundefinedになります。
404ページを必ず置く
path="*"はどのルートにも当たらなかったときの受け皿です。置かないと真っ白になり、ユーザーは壊れたと思います。
import { Link } from 'react-router-dom'
function NotFoundPage() {
return (
<div className="min-h-screen bg-sky-50 p-8">
<h1 className="text-2xl font-bold text-sky-800">ページが見つかりません</h1>
<p className="mt-2 text-sm text-slate-600">
URLがまちがっているか、その鳥はまだ図鑑にいないようです。
</p>
<Link to="/" className="mt-6 inline-block text-sm font-bold text-sky-600">
← 一覧にもどる
</Link>
</div>
)
}
export default NotFoundPage戻り道(一覧へのリンク)を必ず付けるのがコツです。
公開したときだけ404になる問題
手元では動くのに、公開したら/birds/1を直接開いたときだけ404——これはルーティングを入れた人がほぼ全員通るつまずきです。
原因は単純で、サーバーに/birds/1というファイルが無いからです。ページを分けているのはブラウザの中のReactで、サーバーから見ればファイルはindex.html1枚しかありません。
対処は「どのURLでもindex.htmlを返す」設定を1つ足すことです。
/* /index.html 200Cloudflare PagesとNetlifyはこの1行(public/_redirectsに置く)で解決します。ホスティングによって書き方は違いますが、探す言葉は「SPAフォールバック」か「rewrite index.html」です。
いま起きている「気持ち悪さ」
詳細ページは、いまこうしています。
useEffect(() => {
fetch('/birds.json')… // 一覧ページでも同じことをしている
}, [id])同じデータを2つのページがそれぞれ取りに行っています。 動きますが、無駄ですし、片方で鳥を足しても片方に反映されません。
これは「データを1か所に置いて、どのページからでも読めるようにしたい」という要求です。次回のContextがその答えです。
公式ドキュメントも見てみる
reactrouter.com外部サイトRouting | React RouterReact Router公式。この回で使った書き方(宣言的ルーティング)の手順がまとまっています。英語ですが、コードを追うだけでも十分読めますこのレッスンのまとめ
- Reactは何もしないと1ページ。分けるにはReact Routerのような道具が要る
<BrowserRouter>で包み、<Routes>と<Route>で対応表を書くpath="/birds/:id"の:idは何が来てもいい部分。path="*"は404の受け皿- アプリ内の移動は
<Link to="…">。<a>だと状態が全部消える useParamsが返すのは文字列——数値のidと比べるときは型をそろえる- 公開時だけ404になったら、
/* /index.html 200(SPAフォールバック) - ページが増えると同じデータを2か所で持つ問題が出る → 次回のContextへ

