react-router-domのSwitchコンポーネントは必要なんでしょうか。別になくとも動くんですが、という疑問から書き始めた文章です。
Switchコンポーネントがなくても動く
この場合も普通に動作します。
import React from 'react'
import { BrowserRouter, Route, Link } from 'react-router-dom'
import Home from './Home'
import About from './About'
import Dashboard from './Dashboard'
const App = () => {
return (
<BrowserRouter>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
<Link to="/">Back To Home</Link>
</BrowserRouter>
)
}
問題が起こりうる状況
問題が発生するのは以下のような場合です。
userのidとかをpath parameterとして渡したい時このようなコードを書くと思います。この場合 <About/>
と<User/>
はどちらも/about
で表示されてしまいます。
import React from 'react'
import { BrowserRouter, Route, Link } from 'react-router-dom'
import Home from './Home'
import About from './About'
import User from './User'
const App = () => {
return (
<BrowserRouter>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/:user" component={User} />
<Link to="/">Back To Home</Link>
</BrowserRouter>
)
}
これはSwitchコンポーネントを親要素とすることで防ぐことができます。
import React from 'react'
import { BrowserRouter, Route, Link, Switch } from 'react-router-dom'
import Home from './Home'
import About from './About'
import User from './User'
const App = () => {
return (
<BrowserRouter>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/:user" component={User} />
</Switch>
<Link to="/">Back To Home</Link>
</BrowserRouter>
)
}
しかし、<User />
が<About />
の兄要素として配置されると/about
でも常に<User />
が表示されます。
import React from 'react'
import { BrowserRouter, Route, Link, Switch } from 'react-router-dom'
import Home from './Home'
import About from './About'
import User from './User'
const App = () => {
return (
<BrowserRouter>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/:user" component={User} />
<Route path="/about">
<About /> // 表示されない
</Route>
</Switch>
<Link to="/">Back To Home</Link>
</BrowserRouter>
)
}
公式ドキュメントを読む
React Router: Declarative Routing for React
Now, if we’re at /about, will start looking for a matching . will match and will stop looking for matches and render . Similarly, if we’re at /michael then will render.
まぁ要は最初にマッチしたコンポーネントをレンダリングするようです。
ちなみに
以下のようなコードだと先に<User />
がマッチしてしまうため、<Switch />
を使用しても<Dashboard />
は表示されません。こんなコードないと思う。
import React from 'react'
import { BrowserRouter, Route, Link, Switch } from 'react-router-dom'
import Home from './Home'
import About from './About'
import User from './User'
import Dashboard from './Dashboard';
const App = () => {
return (
<BrowserRouter>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/:user" component={User} />
<Route path="/:id" component={Dashboard} />
</Switch>
<Link to="/">Back To Home</Link>
</BrowserRouter>
)
}
使うべきなのか?
<Switch />
のコードをみる限り、脳死で使えばいいかと問われると素直に頷けない感じがします。仕様から察することができると思いますが、ルーティングのたびに子要素(<Route />
)のpropsを順番に検証しているためです(この部分)。そのため、後に配置された要素ほど単純に時間がかかると考えられます。多分。
なので、大規模であればURLを適切に設計し<Switch />
を使用しないという選択があってもいいのかなと思います。まぁ本稿の例みたいに極端なのは流石にないだろ。
const App = () => {
return (
<BrowserRouter>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
// めっちゃたくさんのRouteが配置された場合、末弟のこいつは最後にマッチすることになる。
<Route path="/:user" component={User} />
</Switch>
<Link to="/">Back To Home</Link>
</BrowserRouter>
)
}
結論
WebサービスのURL設計って大事だね。