ルーティングについて、こちらの書籍より学んだことをまとめています。
以前に、ルーティングについてはreact-router-domについて、こちらに基本的な内容をまとめていますが、少し異なるのと、更に深堀りしています。
基本的なルーティング
ルーティングの基本的な使い方を、実際に以下5つのリンクを作って見ていきます。
- Company Website
- About
- Events
- Products
- Contact
ルーティング作成のステップ
- ルーティングの関数(コンポーネント)を作成
- index.jsのAppコンポーネントにルーティングを設定
- 全てコンポーネントの親コンポーネントであるAppに、Routeを設定
- コンポーネントにLinkを使ってリンクを設定
- 存在しないパスの処理を404ページを作成して設定
ルーティングの関数(コンポーネント)を作成
srcディレクトリにpages.jsファイルを作成し、この中にルーティングの関数を作成します。
export function Home() {
return (
<div>
<h1>[Company Website]</h1>
</div>
);
}
export function About() {
return (
<div>
<h1>[About]</h1>
</div>
);
}
export function Events() {
return (
<div>
<h1>[Events]</h1>
</div>
);
}
export function Products() {
return (
<div>
<h1>[Products]</h1>
</div>
);
}
export function Contact() {
return (
<div>
<h1>[Contact]</h1>
</div>
);
}
index.jsのAppコンポーネントにルーティングを設定
react-router-domからBrowserRouterをimportし、index.jsのAppコンポーネントにルーティングを指定します。
これで、App配下にルーティングが適用されました。
import { BrowserRouter as Router } from "react-router-dom";
ReactDOM.render(
<Router>
<App />
</Router>,
document.getElementById("root")
);
全てコンポーネントの親コンポーネントであるAppに、Routeを設定
上記で、Appにルーティングが使用できるようにしたので、Appコンポーネントの中に各リンクのパスを設定します。
import { Routes, Route } from "react-router-dom";
import { Home, About, Events, Products, Contact } from "./pages";
function App() {
return (
<div>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/events" element={<Events />} />
<Route path="/products" element={<Products />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</div>
);
}
export default App;
コンポーネントにLinkを使ってリンクを設定
それではリンクを設定していきましょう。
一番最初に作成したルーティング関数にLinkを追加します。
まずはHomeから。
Homeに、navタグで囲ってリンクを追加します。
このnavタグは、主要なナビゲーションを表します。
export function Home() {
return (
<div>
<h1>[Company Website]</h1>
<nav>
<Link to="about">About</Link>
<Link to="events">Events</Link>
<Link to="products">Products</Link>
<Link to="contact">Contact us</Link>
</nav>
</div>
);
}
これによってできたのがこちら。4つのリンクができ、それぞれ、ちゃんとルートパスに飛んでいますね!
存在しないパスの処理を404ページを作成して設定
404エラーページのルートのパスには*を指定します。
こうすることで、存在しないルートが指定されたときに404コンポーネントが描画されます。
export function Whoops404() {
return (
<div>
<h1>Resource not found</h1>
</div>
);
}
Whoops404のimportと、Routeの追加をします。
import { Routes, Route } from "react-router-dom";
import { Home, About, Events, Products, Contact, Whoops404 } from "./pages";
function App() {
return (
<div>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/events" element={<Events />} />
<Route path="/products" element={<Products />} />
<Route path="/contact" element={<Contact />} />
<Route path="*" element={<Whoops404 />} />
</Routes>
</div>
);
}
export default App;
※全てのRouteコンポーネントはRoutesの配下に記述しないといけません。
できたのがこちら。
でたらめのpathを入力すると404に飛びました!
しかし、これには少し問題があります。
これだと、ページが存在しなかったことを教えてくれますが、どのページが存在しなかったのかがわかりません。
そこで、これを解決するためにuseLocationフックを使用します。
このuseLocationを使うと、現在のページの情報を取得することができます。
import { useLocation } from "react-router-dom";
export function Whoops404() {
let location = useLocation();
return (
<div>
<h1>Resource not found at {location.pathname}</h1>
</div>
);
}
これで、存在しなかったページを教えてくれるようになりました!
ネストされたルート
以下のような階層のルーティングを作りたいとします。
Home Page
└ About
└ History
HistoryがAboutにネストしていますが、このような場合の記述の仕方を見ていきます。
以下のようにRouteをネストするだけでいいんですね〜。
<Route path="about" element={<About />}>
<Route path="history" element={<History />} />
</Route>
そして、親コンポーネントであるAboutに、「Outlet」と言うコンポーネントを子コンポーネントとして記述します。
import { Link, useLocation, Outlet } from "react-router-dom";
export function About() {
return (
<div>
<h1>[About]</h1>
<Outlet />
</div>
);
}
Outletの部分には、locationに対応するパスの子コンポーネントが描画されます。
例えば上記の場合、locationがlocalhost:3000/about/historyなので、Historyコンポーネントが描画されます。
リダイレクト(Navigate)
以前に使用されていたけど、現在はパス名が変わったというような場合、正しいルートへリダイレクトされるようにすることができます。
それには、Redirectコンポーネントを使います。
localhost:3000/servicesにアクセスされたときに、localhost:3000/about/servicesにリダイレクトする例を実装します。
function App() {
return (
<div>
<Routes>
<Route path="/" element={<Home />} />
<Route path="about" element={<About />}>
<Route path="services" element={<Services />} />
<Route path="history" element={<History />} />
<Route path="Location" element={<Location />} />
</Route>
<Route path="events" element={<Events />} />
<Route path="products" element={<Products />} />
<Route path="contact" element={<Contact />} />
<Route path="*" element={<Whoops404 />} />
<Navigate from="services" to="about/services" />
</Routes>
</div>
);
}
ところがRedirectを使おうとすることこんなエラーが
export ‘Redirect’ (imported as ‘Redirect’) was not found in ‘react-router-dom’
こちらに記載がありました。
RedirectをNavigateに変更します。
しかし、さらにConsoleにこんなエラーがでました。
Uncaught Error: [Navigate] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>
こちらのエラーを修正します。
Navigateのルートを以下のように変更し、うまくいきました。
<Route path="services" element={<Navigate to="/about/services" />} />
できたのがこちら
/servicesにアクセスすると、/about/servicesにリダイレクトされることが確認できましたね!!!
ルーティングパラメータ
URLで与えられたパラメータをコンポーネント内で参照することもできます。
ユーザーが色を選択すると、色の詳細情報が表示される機能を実装していきます。
URLに含まれるIDを読み取り、指定された色の情報を表示します。
ColorListコンポーネントを表示する「/」パスと
ColorDetailsコンポーネントを表示する「:id」パスを設定します。
export default function App() {
return (
<ColorProvider>
<AddColorForm />
<Routes>
<Route path="/" element={<ColorList />} />
<Route path=":id" element={<ColorDetails />} />
</Routes>
</ColorProvider>
);
}
パラメータの取得ができるフックuseParamsを使う
上記では、ColorDetailsコンポーネントのpathに:idを指定していますが、そのidを取得する方法があります。
useParamsフックを使用します。
import { useParams } from "react-router-dom";
export function ColorDetails() {
let params = useParams();
console.log(params)
省略
最終のできたコードがこちら
export function ColorDetails() {
let { id } = useParams();
let { colors } = useColors();
let foundColor = colors.find((color) => color.id === id);
console.log(id);
return (
<div>
<div
style={{
backgroundColor: foundColor.color,
height: 100,
width: 100,
}}
></div>
<h1>{foundColor.title}</h1>
<h1>{foundColor.color}</h1>
</div>
);
}
この操作でやっていることはこちらです。
- red, blue, greenの3色を追加し、colors配列を作ります。
- そのcolorの持つidと、パラメーターのidを照合し、idが一致したオブジェクトを変数foundColorに代入。
こちらの操作の場合、3つあるオブジェクトの内、呼び出しているのはこちらになります。
{id: '7ca828b4-56f1-4b89-82a7-41b2e64aadab', title: 'red', color: '#dd08a5', rating: 0}
これで、パラメータを使用したJSXの表示ができました!
以上、ご覧いただきありがとうございました。
コメント