目的
ReactもReduxもあんまり知らない状況から、50時間くらいかけて、みっちりReact+Material-UIなアプリを作った。忘れないように知見をまとめ、また共有する。想定読者は、「React+Reduxを触ったことがある」くらいな人とか、「1回だけReact+Reduxアプリを作ったことがある」くらいな人。
技術スタック
- サーバ側
- Node
- Express (Webフレームワーク)
- FeathersJS (Expressで動作するRESTサーバ作成ライブラリ)
- Passport (Expressで動作する認証ライブラリ)
- クライアント側
- React
- Redux
- Material-UI v.1
- 開発環境
- GCP t1.micro (開発マシン, 無料枠)
- ssh + vim (コード書く用)
- chrome (閲覧用, 開発ツール)
- create-react-app (Reactのスターターキット)
作るもの
シンプルなCRUDアプリ。百人一首を覚えたいなーというモチベーションがあったので、それを管理するアプリ。機能は以下:
- CRUD機能
- 百人一首の一覧、作成、編集、削除
- ログインユーザ用機能
- お気に入り追加・削除
- お気に入りの歌のみ一覧機能
スクリーンショット:
アプリのうりはこんな感じ。技術スタックを反映したものなので、これといった独自性はない。
- リアクティブ
- 画面遷移なし
- SPA
- モバイルフレンドリー
- ナビゲーションバー等
- PWA ready
知見01: Material-UIは v1を使う
Material UI は、ver 0.x と ver 1.x がある。npmのデフォルトで入るのは ver 0.x であり、 ver 1.x は現時点(2018-Mar)ではベータだが、ver 1.x はもう1年以上開発してるし、オフィシャルでも使うよう推奨しているし、使い勝手がかなりよくなっているので、新しく使う場合は(商用での利用も含めて)、ver 1.x を採用しない理由がない。
私は最初、ver 0.x を使っていたのだが、ver 1.x にしてやっぱ断然書きやすいわーと思った。
インストールは
npm install --save material-ui@next
ドキュメントは https://material-ui-next.com
知見02: ReduxのDocは穴が開くほど読む
最近Qiita上では Redux が使いづれーわ みたいな論調があるが、どう考えてもRedux使わない方がつらい(まあ別の状態管理ライブラリを使えば?という異論はあるとおもう)。
Reduxが使いづらいと感じるのは Reduxの示す思想が身に染みてないからだと思う。公式ドキュメントをがっつり読んで、サンプルの ToDo アプリを穴が開くほど眺めて、どうしてこのような構成になっているのかを100%理解してから、自分のアプリの設計を始めるのが、急がば回れでいいと思う。自分はこの作業に20時間くらいはかけた。おかげで redux, react-redux に関してはかなり自信がついた。
ただ、redux-saga はいらないかなー。少なくとも非同期処理をしたいがために導入するのはちょっと大げさな気がする。実際今回は入れなかった(後述)。
知見03: CUD はまとまる/まとめろ
SPAに限ったことじゃないんだけど、Create/Update/Delete は一つの View/Component にまとめるのが吉。ロジックもビューも似てるからね。
Createでは ID を空欄にしてdisable にするとか、Deleteではすべてのフィールドを disable にするとか、多少の味付けはしよう。
知見04: REST発行と状態同期
「RESTを発行してサーバの状態を変更し、成功したらローカルの状態を変更する」というのは非常に多くみられるパターンだ。サーバ状態の変更は、どうしても非同期になるので、非同期処理が挟まる状態管理になる。Redux Middleware を使わなくても、うまくいく。
具体的には、mapDispatchToProps
で、propsに混ぜ込む関数を非同期にして、なかで await
して結果を得たら dispatch
する。サンプルコードではこんな感じ。お気に入り登録関数 addFav(id)
を props に混ぜ込む。
const mapDispatchToProps = (dispatch, ownProps) => ({
addFav: async (id) => {
await addFavToServer(id)
dispatch(addFavToLocal(id))
},
})
addFavToServer()
がREST呼び出しをする非同期関数で、addFavToLocal()
が Action Creator。
知見05: ファイルを分けすぎない
React+Redux で基本に忠実にアプリを書こうとするとファイル数がめっちゃ多くなる。さて、Reduxに関連する考え方に Ducks というのがある。Qiitaでも記事あるし、適当にググればいくらでも例があるので見てほしいが、要は密結合なのに別々の場所に格納するのはおかしいだろう、というのが発想の中心で、大いに賛同できる。
作ったアプリでは、以下を一つのファイル mylogic.js
にまとめた。それでも100行に満たないサイズ。分ける必要なんてなかったんや。
- Action (そもそも定数定義すらしてない)
- Action Creator 9個
- Reducer 3つとそれを combine するコード
- createStore とサーバに状態の初期値を取りに行くコード
- exportするのは createStore した store
最後に
はじめてSPA作ったけど、というかJavaScriptを本格的に触ったのも最近なんだけど、ほんとこの辺の技術の進化がすごすぎる。もうサーバサイドでごりごりアプリを書く時代は終焉するんだろうなーという予感をバリバリ感じた。