5分と5秒かけて作成・デプロイしたTypescript + React + Firebase アプリに 、URLで表示を分ける機能:ルーティング機能を付け加えていきます。
アプリのディレクトリ構成はこんな感じ。基本的にはcreate-react-app
直後と変わりません。
.
|-- README.md
|-- build # 以下略
|-- firebase.json
|-- node_modules # 以下略
|-- package.json
|-- public # 以下略
|-- src
| |-- App.css
| |-- App.test.tsx
| |-- App.tsx
| |-- index.css
| |-- index.tsx
| |-- logo.svg
| |-- react-app-env.d.ts
| `-- serviceWorker.ts
|-- tsconfig.json
`-- yarn.lock
React Router DOM の導入
yarn add react-router-dom
yarn add @types/react-router-dom # typescriptプロジェクトではこちらも必要
これでreact-router-dom
(v5.0.1) がインストールされました!
サンプルを読む
まず、サンプルを読んで使い方を勉強していきます。
基本的な使用例
クイックスタート : 基本的なルーティングのコードをそのままsrc/App.js
に張り付けて動作させると・・・
なるほど、コンポーネントを定義して
function Index() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
function Users() {
return <h2>Users</h2>;
}
URLとコンポーネントを紐づけて
<Route path="/" exact component={Index} />
<Route path="/about/" component={About} />
<Route path="/users/" component={Users} />
任意の要素にLINKの役割を持たせるって感じか
<li>
<Link to="/about/">About</Link>
</li>
こちらはかなり直感的に使うことができそうです。
応用的な使用例
クイックスタート : ネストされたルーティングのコードをそのままsrc/App.js
に張り付けて動作させると・・・
なるほど、/topics/components
や/topics/props-v-state
のような場合ですね。
コードはどうなるのか見ていきましょう。
/topics
に入るとまずはTopics
コンポーネントにルーティングされるようです
function App() {
return (
<Router>
<div>
<Header />
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
</div>
</Router>
);
}
Topics にルーティングされた場合に、引数 match が流れ込んできて、
match.url
で URLを引き継ぐ(ネストさせる)ことができるように見えます。
function Topics({match}:Props) {
return (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${match.url}/components`}>Components</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>Props v. State</Link>
</li>
</ul>
id
という名前の引数で/topics
以下にネスとしてきた文字列を受け取って、Topic
コンポーネントに紐づけているように見えます。
ネストしなかった場合はPlease select a topic.
をh3
で表示させる処理も書かれていますね。
<Route path={`${match.path}/:id`} component={Topic} />
<Route
exact
path={match.path}
render={() => <h3>Please select a topic.</h3>}
/>
</div>
);
}
Topic
コンポーネントは、Topics
と同様に引数 match をとるコンポーネントのようです。
match は、id?
を引数にとるRouteComponentProps
をextends
しているので、match.params.id
という呼び出しができるのでしょう。
interface Props extends RouteComponentProps<{ id?: string }>{} // TypeScript対応で付け加え
function Topic({match}:Props) {
return <h3>Requested Param: {match.params.id}</h3>;
}
こちらは読解にあまり自信がないですが、何とか使うことはできそうです。
マネしてみる
自分のアプリでもreact-router-dom
を使ってみます。
現在作成中のe-Sports専用のクラウドファウンディング・サービス「e-Sports-Funding(仮)」のルーティング構成はこんな感じがいいかな
-
/
: トップページ -
/create
: プロジェクト作成画面 -
/search
: プロジェクト検索画面 -
/project/:project_id
: プロジェクト詳細画面 -
/funding/:project_id
: プロジェクト出資画面 -
/mypage/
: マイページ
基本的な使用例
ネストは無いものとしてルーティング
それぞれのコンポーネントたちをsrc/components
以下に定義して、App.tsx
でURLとコンポーネントを紐づけるだけなので、これは簡単です。
応用的な使用例
-
トップページ・プロジェクト作成画面・プロジェクト検索画面・マイページはどこからでも行ける
-
プロジェクト詳細画面はプロジェクト検索画面から引数
:project_id
をとった場合に行ける -
プロジェクト出資画面はプロジェクト詳細画面から引数
:project_id
をとった場合に行ける
みたいな、比較的複雑なルーティングを構成してみます。
App.tsx
にURLとコンポーネントを紐づける設定をすべて書いて、コンポーネントではリンクの設置と、引数の受け渡しのみを行うようにしました。
全員の親となるコンポーネントにルーティング設定を並べたほうが、一覧性が高くて良いかもしれませんね。
リダイレクトも試してみました。
const App: React.FC = () => {
return (
<Router>
<div>
{Header()}
<Route exact path="/" component={Toppage}/>
<Route path="/create" component={CreateProject}/>
<Route path="/search" component={SearchProject}/>
<Route path="/project/:project_id" component={ProjectDetail}/>
<Route exact path="/project" render={()=>(<Redirect to="/search"/>)}/>
<Route path="/funding/:project_id" component={Funding}/>
<Route exact path="/funding" render={()=>(<Redirect to="/search"/>)}/>
<Route path="/mypage" component={Mypage}/>
</div>
</Router>
);
}
今後の展望
ルーティングができたので、次はいよいよ画面!
Material UIで見た目を整えていこうかと思います。
その次は状態変化の制御、続いてデータベースの導入になるのかな。
完成が待ち遠しいです。
参考ページ
- 最も信用できる1次情報
- match の型が分からなかったので参考にした