React+Redux環境でreact-router@v4への移行をおこなう
React Routerの4系がリリースされて久しいですが、相変わらず対応ができていませんでした。 ようやく重い腰を上げてアップデートしたのですが、噂に違わず障壁が多い移行だったため、メモがてら記録を残しておきます。
v3 → v4で何が変わったか
簡潔に言うと、とても良くなりました。
- ルーティングコンポーネントのネストについての制約(縛り)が解消された。
- contextを利用せずにパラメータを送れるようになった。
現在の状況
- React+Reduxで構築されたサービスです。
- react-router3系とreact-router-reduxを併せて利用していました。
- 画面遷移はhistroyに対するrouter.push()がメインです。
<button onClick={context.router.push()} />
移行作業
パッケージの更新
今回更新したパッケージは以下の通りです。
react-router@3.0.0 → react-router-dom@4.2.2
- DOMのみパッケージ分割されていましたが、こちらで事足りました。
react-router-redux@4.0.8 → @next
- 4系への対応は@nextバージョンを利用するように、とのことでした。
- それ以前のバージョンは2/3系用となっています。
query-string
- クエリパラメータ取得に使います。
ルーティング部分
新たなルーティングがこちらです。
import React from 'react'; import { render } from 'react-dom'; import { HashRouter, Route, Switch } from 'react-router-dom'; import { createHashHistory } from 'history'; import { Provider } from 'react-redux'; import { ConnectedRouter } from 'react-router-redux'; : const history = createHashHistory(); const store = configureStore(history); render( ( <Provider store={store}> <HashRouter> <ConnectedRouter history={history}> <NaviComponent> <Switch> <Route exact path="/" component={Top} /> <Route path="/contents/:id" component={Contents} /> <Route path="/contents" component={Contents} /> </Switch> </NaviComponent> </ConnectedRouter> </HashRouter> </Provider> ), document.getElementById('app'), );
- ConnectedRouterがreduxと連結したhistoryを注入してくれます。
- Hashによるルーティングを利用しているのでHashRouterで括っています。
- NaviComponentのように共通のコンポーネントはそのまま組み込めます。
- Switchで括っておくと、マッチするRouteが複数あっても最初にマッチしたコンポーネントしか表示しません。
- pathは"/contents(/:id)"と書けなくなってしまったため、2行に分けて記載しています。
- もっと良い方法があればコメントなどください。
- URLパラメータの:id引き渡しについても以下の通り変更がありました。
- props.params.id + props.match.params.id
アクションの置き換え
- push / replace / go / goBack等のファンクションはcontext.router内から取得していましたが、withRouter()メソッドの登場によって、Route直下にない孫コンポーネントにもprops経由でこれを送ることができるようになりました。
import { withRouter } from 'react-router-dom'; : export default withRouter(Component);
- また、相対パスが利用できるようになったことも注意が必要でした。
- this.context.router.push('contents'); + this.props.history.push('/contents');
contextを廃止
公式ドキュメントにもあるように、contextは非推奨仕様でした。そもそもReactRouterの実装のために用いていたので、これを機にすべて撤廃することにしました。
クエリパラメータの対処
const search = props.location.search; // ='?key1=hoge&key2=fuga' const params = perse(search); // = { // key1: 'hoge', // key2: 'fuga', // }
- また、Switchからも見て取れるように、パスでのみコンポーネントが切り替わるためクエリの変化はpropsに流れてこなくなりました。
所感
主に詰まったところしか記載していないのですが、大概の情報はこちらのページで仕入れる事ができました。 reacttraining.com
以下のサイトにもお世話になりました。 qiita.com
今回のredux連携のようなケースは単体でのパッケージ導入と異なり、公式ドキュメントだけだとなかなか追いづらいところもありましたが、開発者側も周辺パッケージを意識しているようで、今回のアップデートはかなりreduxに寄せたものだったとも思いました。
今後もナレッジについてはメモがてら残していこうと思います。
補足
1018/05/18訂正
サンプルのコードで、HashRouter と ConnectedRouter のネストが逆になっていました。今のコードは訂正後のコードになっています。
HashRouter から振ってきたものを history 反映しないとダメですよね… 手元で起きた不具合としては、「history が一巡遅れて」いました。
Reactビギナーズガイド ―コンポーネントベースのフロントエンド開発入門
- 作者: Stoyan Stefanov,牧野聡
- 出版社/メーカー: オライリージャパン
- 発売日: 2017/03/11
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
- 作者: 久保田光則
- 出版社/メーカー: 技術評論社
- 発売日: 2017/05/26
- メディア: Kindle版
- この商品を含むブログ (1件) を見る