モバイルアプリのようなUIを実装したいなーと思い、OnsenUIのサンプルのtodoアプリと同じようなものをReactとReduxを使って作りました。
下記のようなUIパーツをもったアプリを作ってみました。
- ヘッダーのツールバー
- リスト
- サイドメニュー
- フッターのタブ
- モバイルっぽいページ遷移
成果物はこちらにあります。
ソースはこちらに置いてあります。
ビルド環境
フレームワークにはReactを使いました。
create-react-appを使ってreactアプリケーションの雛形を作りました。
webpackの設定に辟易していたので、こういったボイラープレートはさくっと作るレベルの開発の時には嬉しいですね。
CSS Modulesには対応していないようで、そこが玉に瑕。
OnsenUI
UIライブラリは以下の基準で選びました。
- モバイルっぽい見た目と動きが実現できる
- Reactとの相性が良い(できればReactコンポーネントとして使いたい)
- 小さいUIパーツだけでなく、画面遷移・リスト・サイドメニューなどの大きなレベルのパーツも揃っている
ionic、Material-UI、jQueryMobile、UIkitなども見ましたが、今回はモバイルUIに特価しているOnsen UIを選びました。
OnsenUIは生のJSだけでなく、React、Angular、VueなどのJSフレームワークに対応しています。
リリース頻度も高いのでちゃんとメンテナンスされていそうです。
Reactで使うにはreact-onsenuiというプラグインを使う必要があります。
OnsenUIは結論から言うとかなり使いやすかった
- パーツがコンポーネント化されてReactナイズされていて、簡単に使用することができた
- コンポーネントの粒度が結構大きいので細かい所までカスタマイズするのには向いてなさそう
- だけど、ざっくりアプリっぽい画面遷移を作りたいときには便利
- Reactのドキュメントが充実している(実装している時はこのページを常に参照していました)
- CSSの実装例も豊富
- 最悪ソースを読めば実装がわかる
- 今回はほぼCSSで手直しすることなく実現できた
Navigator, Splitter, MainPage, SubPage等の構造
主要なコンポーネントの構造はこのようにしました。
<Navigator>
<Page>
<Splitter>
<SplitterSide>
<SideMenu />
</SplitterSide>
<SplitterContent>
<MainPage />
</SplitterContent>
</Splitter>
</Page>
</Navigator>
Reduxでfluxっぽく
ReactとReduxはかなり浸透しているのでもはや黄金コンビではないでしょうか。
導入についてはこちらの記事を参考にしました。
ReduxをReactで使うためのプラグインにreact-reduxを使いました。
Reduserからアプリ全体のstateをpropsとしてComponentが受け取り、それを元にUIを表示させます。
Componentからのイベント(タップやキーボード入力)を受け取って、ActionCreatorでActionを生成させてReduserへとdispatch(伝送)します。
相関イメージ図
使ってみてざっくりと下記のような印象でした。
- reactのstateを外部管理することで、アプリケーション全体のstateとして管理できる
- 「子コンポーネントから親コンポーネントに何か伝えたい時 → actionを投げる」みたいな使い方(合ってんのかわからんけども)
- stateを複数コンポーネントで共有したい時にreduxのstoreを使う
どのタブを開いているか、サイドメニューが開いているかどうか、といった表示のためだけの情報もstoreのstateに載せましたが、本当は分けるべきなのかなーと思いつつ良い解を見つけられませんでした。
もしかしたらreduserをある程度の粒度(ページ単位?)で切り分けるのがいいのかもしれませんが試してないです。
Reduxで非同期通信
Reduxで非同期通信をいい感じに扱うために今回はredux-thunkというミドルウェアを使ってみました。
作ったサンプルでは非同期通信は発生しないのですが、localStorageにアクセスするところを非同期APIに見立てて使っています。
他にもredux-sagaというのもあります。
下記の実装例のように、ActionCreatorでAPI.getTodoというPromiseを返す非同期処理をthenで受けてからdispatchを使うことができます。
class ActionCreator {
getTodo() {
return dispatch => {
Api
.getTodo()
.then(res => {
dispatch({
type: ACTIONS.GET_TODO,
todoList: res,
});
});
};
}
}
所感
久しぶりにReact書きましたが、やっぱり書きやすかったです。
stateとpropsドリブンでDOMを変更していくようにして、直接DOMを操作しないようにしてライフサイクルから逸脱しないようにすれば脱jQueryできて幸せになれそうです。
あと、この作り方を元に、Cordovaとか使ってweb技術だけでモバイルアプリが作れるか試してみたいです。
こちらの記事にそのまんまやり方が書いてあるので、それを実践してみたいです。