reactのRoutingライブラリはreact-routerとreact-router-domがあります。
「react-routerがv4から改称してreact-router-domになったんだ!」みたいな印象がありますが(me too)。厳密にいうと違います。
react-router でググって一番上にくる記事がいきなりnpm install --save react-router-dom とかしてるのでややこしいのですが。
なにはともあれ
READMEを見てみましょう。今はv5です。
react-router-domはDOMバインディングなreact-routerだよ〜って書いてあります。
react-router Declarative routing for React.
react-router-dom DOM bindings for React Router.
ちなみにreact-router-nativeってのもあります。
使い方を比較
Home,About,Dashboardはあらかじめ用意したコンポーネントです。
react-router
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, Switch } from 'react-router';
import { createBrowserHistory } from 'history';
import { Home, About, Dashboard } from './component';
const App = () => {
return (
<Router history={createBrowserHistory()}>
<div>{document.title}</div>
<Switch>
<Route exact path='/'><Home /></Route>
<Route path='/about'><About /></Route>
<Route path='/dashboard'><Dashboard /></Route>
</Switch>
<a href='/'>Back To Home</a>
</Router>
)
}react-router-dom
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch, Link } from 'react-router-dom';
import { Home, About, Dashboard } from './component';
const App = () => {
return (
<BrowserRouter>
<div>{document.title}</div>
<Switch>
<Route exact path='/'><Home /></Route>
<Route path='/about'><About /></Route>
<Route path='/dashboard'><Dashboard /></Route>
</Switch>
<Link to='/'>Back To Home</Link>
</BrowserRouter>
)
}パッと見、違いとしては以下の感じです。 1. react-routerは<Router />にhistoryを渡している 2. react-routerはaタグだが、react-router-domは <Link/> を使用している。
2に関してはのAPIをみた方が早い。 1について調べていきます。
RouterとBrowserRouterの違い
結論から書きますと、この二つにあまり違いはありませんでした。
実装を見てみます。
見た通りですが、BrowserRouterは内部でRouterを使用しており、historyをpropsに渡しています。単なるWrapperですね。
class BrowserRouter extends React.Component {
history = createHistory(this.props);
render() {
return <Router history={this.history} children={this.props.children} />;
}
}PropsTypesではいくつかoptionalなパラメータが定義されていますが、これらのpropsは全てhistoryへ渡されるので、RouterでもcreateBrowserHistoryにパラメータを渡すことで同じようなことが実現できます。
BrowserRouter.propTypes = {
basename: PropTypes.string,
children: PropTypes.node,
forceRefresh: PropTypes.bool,
getUserConfirmation: PropTypes.func,
keyLength: PropTypes.number
};以下はbasenameとforceRefreshを指定した例
const App = () => {
return (
<Router history={createBrowserHistory({ basename: '/', forceRefresh: true })}>
<div>{document.title}</div>
<Switch>
<Route exact path='/'><Home /></Route>
<Route path='/about'><About /></Route>
<Route path='/dashboard'><Dashboard /></Route>
</Switch>
<a href='/'>Back To Home</a>
</Router>
)
}あんまり違わないけど…
react-routerもreact-router-domも「Routingをする」だけならば同じように使えます。useHistory, userLocation, useParams, useRouteMatch といったhooksもreact-routerに実装があります。
ただ、当然のことをいうと、react-routerだけを使用してもあまり嬉しくありません、<Link />や<NavLink />といったAPIが使用できませんしね。
<Router />の活用…?
最後に<Router />の活用を考えてみましょう。前述したようにBrowserRouterはRouterのWrapperなので、<Link />や<NavLink />といったAPIも同じように使えます。 historyを別でinstallしなければなりませんが、まぁいいでしょう。
RouterとBrowserRouterの違いはただ一つ、historyを外部から渡すことができる。 これだけです。 なので、ReactGAと組み合わせてトラッキングが…とか思いましたが、調べたらすでにやってる方がいらっしゃいました。更に言えばuseEffect使う形に落ち着いてた。
https://github.com/react-ga/react-ga/issues/122
更に更に言えばuseLocationを使った例が公式にありました。
結論
迷わずreact-router-domを使おう。
蛇足
ぼんやりとreact-routerのissueを眺めてたらこんなdiscussionがされていました。
react-routerに依存している別のパッケージがあった時に、バージョンが不一致だと競合するからreact-router-domをreact-router配下のパッケージにしようよーみたいな感じですね。 react-router-nativeに全くメリットがないのと、そもそもreact-routerは直接依存するものではない?ようなので、積極的ではないのかなと思いますが。