最近Reactのプロジェクトでルーティングにui-routerを使ってみたので使い方などの紹介
この記事はオプトテクノロジーズアドベントカレンダー13日目のエントリーです。
12日目は @ovrmrw さんの「hyper gatling rx」です
14日目は @hiroshist さんの「AWS Serverless関連で何か」です
ざっくり紹介
もともとAngularJSのrouterライブラリとして有名なui-routerがReactでも使えるというもの
なので、お作法だったりAPIだったりがAngularJSを彷彿とさせる感じで、あまりReact文化圏に馴染む感じではないけど、機能としては充実しててとても便利に使える
いいところ
まあなんか普通に便利(雑
- ui-routerがやはりよく出来ていて、その機能を享受できるのがよい
- guardがreact-routerと違ってjsの世界だけで書ける
- ページ遷移時にPromiseがresolveされるまで待つとか便利
- 他にも調べると色々あって機能的に困るってことはあんまりなさそう
- Reactとの繋ぎ込みについてはrouterのインスタンス作って
<UIRouter>
に食わせてあげるだけなので難しいことはない - 型定義ファイルが含まれている(そもそもライブラリ自体の実装がts)ので、型定義の情報に安心感があるし、exampleも充実しているのでドキュメント読みに行かなくても型定義ファイルだけで相当便利にやれる
つらめなところ
- 情報が少ない(日本語情報は皆無だし、英語で調べてもAngularJSでの情報を参考にする事が多かった)
- Reduxと組み合わせが地味に困る
-
ui-router/redux
はあまりにも機能が足りてない(というかメンテされてない) - そのため、自前でインテグレーションを書くことになる
-
- ui-routerでのルーティング定義のことを
State
と称しているので、微妙に紛らわしい - ReactComponentのpropsへ値をinjectするなど、微妙に型定義に困る動作がある
現在のプロジェクトで使ってみての所感としては、問題なく使えるしui-router固有の問題で困らされたことはあまりなかったので普通に使っていいと思った
使い方とか
サンプルリポジトリ: https://github.com/sisisin-sandbox/ui-router-in-react
普通にReactで使う
最低限これだけ
import { pushStateLocationPlugin, UIRouter, UIView } from '@uirouter/react';
import React, { Component } from 'react';
import { Home } from './components/Home';
import { Menu } from './components/Menu';
import { User } from './components/User';
const routerStates = [
{
name: 'home',
url: '/home',
component: Home,
},
{
name: 'user',
url: '/users/:userId',
params: {
userId: {
type: 'int',
},
},
component: User,
},
];
class App extends Component {
render() {
return (
<UIRouter states={routerStates} plugins={[pushStateLocationPlugin]}>
<>
<Menu />
<UIView />
</>
</UIRouter>
);
}
}
export default App;
パラメータを使う
以下のようにrouterのstateの url
プロパティで :userId
のように指定すると、parameterを取得するAPIを使って値を取れるようになる。
このときのparamsに関する設定を別途 params
プロパティで指定可能で、例えば type
を指定すると取得時にその型に変換しておいてくれるなど、便利機能が満載
const routerStates = [
{
name: 'user',
url: '/users/:userId',
params: {
userId: {
type: 'int',
},
},
component: User,
},
];
ページ遷移前にPromiseを解決して、その結果をpropsとして扱う
router stateのresolve
プロパティに解決したいPromise及び、その結果をpropsにどんなプロパティ名でinjectするかを指定してやる
{
name: 'home',
url: '/home',
component: Home,
resolve: [
{
token: 'resolvedValue', // props.resolvedValueでアクセスが可能になる
resolveFn: () => Promise.resolve('resolve!'),
},
],
},
Reactの中でrouterのAPIを使う
statesで指定したComponentのpropsにrouter周りのインスタンスがinjectされているので、それを使う
この例では パラメータを使う
のstateに対応するコンポーネントとして記載。
export const User = ({ transition }: { transition: Transition }) => {
const { userId } = transition.params();
return (
<div>
user {userId}. typeof userId is {typeof userId}
</div>
);
};
実際の表示↓
storybookと共存する
他のrouterライブラリ同様、メモリルーターを使う
import { storiesOf } from '@storybook/react';
import { memoryLocationPlugin, ReactStateDeclaration, UIRouter } from '@uirouter/react';
import React from 'react';
import { Menu } from '../components/Menu';
const plugins = [memoryLocationPlugin];
const states: ReactStateDeclaration[] = [];
storiesOf('Menus', module).add('Menu', () => {
return (
<UIRouter states={states} plugins={plugins}>
<Menu />
</UIRouter>
);
});
Reduxと合わせて使う
Reduxと組み合わせて使うときも大体そのまんまでよいが、一部ハマるので注意
- routerのシングルトンを自前でインスタンス化するときは
UIRouter
コンポーネントにplugins
やstates
を食わせず、routerインスタンスに自分で設定して上げる必要がある
export const router = new UIRouterReact(); // routerのインスタンスを使いたいので、自前でnewする
const routerStates = [
{
name: 'home',
url: '/home',
component: Home,
},
{
name: 'user',
url: '/users/:userId',
params: {
userId: {
type: 'int',
},
},
component: UserConatiner,
},
];
// 自前でrouterをnewして使う場合はpluginやstatesは事前に解決した上で<UIRouter>コンポーネントにrouterだけを渡すようにしないと実行時エラーになる
router.plugin(servicesPlugin);
router.plugin(pushStateLocationPlugin);
routerStates.forEach(s => router.stateRegistry.register(s));
export const store = createStore(
combineReducers({
users: userReducer,
}),
);
export type AppState = typeof store extends Store<infer S, any> ? S : never;
class App extends Component {
render() {
return (
<Provider store={store}>
<UIRouter router={router}>
<>
<Menu />
<UIView />
</>
</UIRouter>
</Provider>
);
}
}
export default App;
その他の実装パターン
ui-router公式で提供しているサンプルリポジトリ があるので、これを見ると大体ある(というか自分が頑張って書いてもこのリポジトリ以上のことはそんなに書けない。。)
まとめ
というわけでui-router使い方紹介でした。
色々出来て便利なのでみんな使おう。