react-router-domでルーティングを作成する
この記事は下記のシリーズの記事の 1 つです。
関連シリーズ:自分用の Dashboard サービスを作成する
開発用リポジトリ
My-Todo-Note は次のリポジトリで管理しています。
この記事の最終結果は次のブランチで確認できます。
SPA のためのルーティング
従来のウェブサイトは表示する画面毎に html ファイルがあり、URL に沿って適切なものがサーバーから配信され、ブラウザで表示されていました。一方、SinglePageApplication(以下、SPA)では html ファイルは 1 つであり、その中身を JavaScript で動的に切り替えることで表示が制御されます。そのため、URL に沿って適切な内容を表示するためには、サーバー側で行っていた html の振り分け作業と似たようなことを、JavaScript で行う必要があります。
これを行ってくれるのがナビゲーション用のライブラリです。React であれば react-router-dom、reach-router が有名です。reach-router の方が後発でスッキリしているという面もありますが、今回はシェアの大きい react-router-dom を使用します。これらのライブラリの製作元は同じなので似通っている部分は多いです。
react-router と react-router-dom
react-router には 3 種あり、コア機能だけがある react-router、コア機能に Web に必要な機能を追加した react-router-dom、ReactNative 用の react-router-native が存在します。
React で通常使用する際は、react-router-dom を使用します。なんとなく react-router の方が正解に思えるのですが react-router-dom が通常は正解です。下記も参考になります。
参考:what's the diff between `react-router-dom` & `react-router`?react-router-dom はアップデートの影響が大きめでやや扱いが難しい
これは個人の感想レベルですが、react-router-dom はメジャーな割にかなり破壊的な変更を行われるライブラリに感じます。また、hooks 以降、よりよい形に進化を予定するようですので気軽にアップデートしにくいライブラリであることは覚えておく必要があります。
参考:The Future of React Router and @reach/routerSwitch と Route の難しさ
react-router-dom にはパスと一致した Component を表示するための Switch と、パスにより表示する関数を制御する Route、各 Route に遷移するための Link という Component を中心に使用します。
Switch と Route の制御は地味に難しく、自分で色々するとどうにも上手くいかずに時間がかかることがあります。幸い、公式ドキュメントにはたくさんの例が紹介されています。それらの使い方をベースにして、自身で必要なだけ拡張できる、使いやすいのはどの方法かを選んで使うことをまずはお勧めします。
この記事では公式ドキュメントの Route Config をベースにまずは実装します。
Route Configreact-router-dom のインストール
ライブラリがインストールされていなければインストールします。
yarn add react-router-com @types/react-router-dom
App.tsx の作成
App.tsx がない場合は作成し、index.tsx で読み込みます。
// index.tsx
// ... 省略
import { App } from "./App";
ReactDOM.render(<App />, document.getElementById("root"));
App.tsx が正しく表示されているかを確認したら、基本的なルーティングを実装していきます。
import React from "react";
import {
BrowserRouter as Router,
Route,
Switch,
Link,
RouteProps,
} from "react-router-dom";
export const App: React.FC = () => {
return <div>App!!</div>;
};
暫定表示用の Component の作成
Home 画面、Dashboard 画面、Login 画面、404 画面の暫定表示用 Component を App.tsx 内に作成します。アクセスする URL によりこれらを表示できるようにします。
// App.tsx
const Home: React.FC = () => {
return <div>Home</div>;
};
const Login: React.FC = () => {
return <div>Login</div>;
};
const Dashboard: React.FC = () => {
return <div>Dashboard</div>;
};
const NotFound: React.FC = () => {
return <div>404 Not Found</div>;
};
route の作成
どの URL でどの Component を表示するかの配列を用意します。後々の拡張を考えて、認証なしで表示できるルートと、認証時に表示できるルートを分けておきます。
path=”*“は、アクセスされたパスに該当する設定のものがなければ表示する設定です。例えば/user、/about といったルートは設定していないため全て*で指定した Component が表示されます。
// App.tsx
const UnauthenticatedRoutes: RouteProps[] = [
{
path: "/",
component: Home,
exact: true,
},
{
path: "/login",
component: Login,
},
{
path: "*",
component: NotFound,
},
];
const AuthenticatedRoutes: RouteProps[] = [
{
path: "/dashboard",
component: Dashboard,
},
];
ルーティングを App に実装します。react-router-dom は Router の子要素でのみ機能するため、App 全体を Router で囲みます。App 内に AppRoutes 関数を作成し、認証なしでアクセスできるものを全て展開します。
// App.tsx
const AppRoutes = () => {
return (
<Switch>
{UnauthenticatedRoutes.map((route, index) => (
<Route key={index} {...route} />
))}
</Switch>
);
};
export const App = () => {
return (
<Router>
<AppRoutes />
</Router>
);
};
ルーティングの確認
ここまでの実装で、/、/login、/その他の URL で該当する内容が表示されるようになっています。各 URL への移動はブラウザから URL へ直接アクセスする方法と、Component 内で Link を使用する方法があります。例えば、次のように Home Component を変更すれば Login へのリンクが表示されるはずです
// App.tsx
const Home: React.FC = () => {
return (
<div>
Home
<Link to="/login">Login</Link>
</div>
);
};
認証ルート用の Route Component の追加
まだ認証はありませんが Route 自体は分けておきます。認証なしのルーティングは Route、認証ありのルーティングには AuthenticatedRoute を使用するルールとします。より細分化が必要になればその時に対応します。
// App.tsx
const AuthenticatedRoute: React.FC<RouteProps> = ({ component, ...rest }) => {
const isAuthenticated = true;
const toRedirectPage = () => {
return <Redirect to="/" />;
};
return (
<Route {...rest} component={isAuthenticated ? component : toRedirectPage} />
);
};
AppRoutes 関数に AuthenticatedRoutes を追加します。
// App.tsx
<Switch>
{AuthenticatedRoutes.map((route, index) => (
<AuthenticatedRoute key={index} {...route} />
))}
{UnauthenticatedRoutes.map((route, index) => (
<Route key={index} {...route} />
))}
</Switch>
これで/dashboard にも遷移可能となります。
ベースレイアウトの作成編へ続く
URL からのアクセスと画面遷移が可能となりました。次の記事では各画面のレイアウトを作成します。