React+Redux覚書
概要
React+Reduxを使ってアプリを書く機会があったが、 どちらもちゃんと触ったのは年単位昔なので思い出すために軽くコードを書いてみた。
ーーやつの備忘録。
こういうことを思ってこうしたいなって気持ちになったという記録。
基本構成
environment
- Docker node:10.4.0-alpine
dependencies
- react 16.4.1
- react-redux 5.0.7
- redux 4.0.0
devDependencies
- babel-loader 7.1.4
- babel-preset-react 6.24.1
- webpack 4.12.9
基礎知識
- React
- Redux
- connect
- state
- reducer
- Component
- Provider
- Container
- Presentational
所感
もともとSyntagme作るときに、Reduxのコードは読んでいたので一度読み直せば「あーはいはい」って感じだった。
ただ、当時思ったActionCreatorの扱いでやっぱり戸惑う。
ActionCreatorは、 * dispatchするオブジェクトを作る * 複雑なdispatchを隠蔽する
の役割があると感じていて、 その2つを共存させることに抵抗がある。
できれば役割わけたいなぁと。
もしかしたらMiddlewareがいい感じに隠蔽してくれるのかも知れないが、 初心者にはその歴史的経緯をさっくり理解するにはReduxの世界は広すぎる。
再設計
というわけで腹落ちする程度まで掘り下げた。
ディレクトリ構成
- src +- index.js +- views/ | +- components/ | +- containers/ | | +- Home.jsx | +- App.jsx +- usecase | +- home.js +- actions/ | +- index.js +- store/ +- index.js +- reducers/
index.js
App.jsx
のマウント- アプリケーション全体の初期化処理
Views
React Componentを押し込める場所。 汎用的なものだけではなく、画面構成全部を含むので、Viewって名前空間にした。
App.jsx
- Providerの構築
- Redux Storeとの接続
Containers
- Container Componentの置き場
- Presentationalを一つ以上組み合わせる
- ViewとUseCase, Stateを接続する
Components
- Presentational Component
- コンテキスト持っちゃ駄目よ
- 小規模ならこれでいいけど、Componentの数が増えてきたらAtomic-Designとかをベースに分割したほうがいいかもしれない
- が、必要ないならしないほうが無難
UseCase
- 独自定義
- 着想はAlminから
- view ← 何らかのイベント → action の中間処理を担う
- fluxで言うところのActionCreator
- view側からの入力のハンドル
- アプリの外側とのコミュニケーション
- dispatchのタイミングのハンドル
- 基本的にはContainerと対応する
Actions
- Actionオブジェクトの作成
- 程よい切り方がわからないけど機能単位で切るのがいいのかなぁ
Store
Redux Storeの定義。
index
- createStoreの実行
- reducer, initialState, middlewareの構築
initial-state
- 初期Stateの定義
reducers
- reducerの定義
- 基本的にはアプリケーションにおける情報設計単位でファイルを切る
まとめ
- React+Reduxで最低限腹落ちする構成を考えた
Macを外部ディスプレイにつなげた時のWindow配置を記憶したい!
背景
最近の僕は、GoogleChromeのタブを38個とか開いているようです。
Tabs Outliner と Spaces という拡張機能を併用して、 たっくさんあるタブを用途やカテゴリ毎にwindowに分割しているんです。
まあ、ぞれでもWindowは5,6個できるんですけど。
Tabs OutlinerとSpacesのおかげで管理は大分楽になったんですが、困ったことが一つありまして。
問題
普段はMac Bookを外部ディスプレイにつなげて普段作業しているんですよね。Mac Bookのディスプレイと外部ディスプレイ二枚。
会議や相談なんかあれば、外部ディスプレイの接続切ってMac Bookを持っていくわけです。 そして話し終えたら席に戻ってきて外部ディスプレイに接続する。
画面にでてくるのは、SlackやiTerm、そして5,6個重なったGoogle Chrome。
微妙に位置を調整して、ワンクリックで目的のWindowを開けるようにしていたGoogle Chromeの位置を戻すのがもう、面倒でしかたないったらありゃしない。
さすがに、疲れました。
調査
そんなわけで、頼れるGoogle先生に聞いてみたんです。できないかって。
参考になったのは、以下の記事でした。
forget-me-not
は残念ながらアクセス出来ませんでした。まあ2012年の記事だし。
代わりにStay の方を見てみました。
AppStoreで\1,800だったので、即買。
検証
先ほどの StayさえあればもうMBAをサブディスプレイに繋げるのは怖くない を見ながら設定してみました。
2,3回試しました。繋いで、はずして。
Google ChromeのWindow7枚とiTermとSlackだけ個別にstoreしてみました。 Mac Bookを開いたままコネクタを外すと、まあ位置画面に収まります。 そのまま繋げ直してみると、「Restoring windows」と表示されてガチャガチャwindowのサイズや配置が変わっていきます。
結論
なにこれ便利...!
お試しあれ
参考
2015年の振り返り
新年早々いろいろあって振り返ってる余裕が無かったので、それっぽいのをハリボテで。
2015年に書いた記事
当ブログ
8記事!少ない!!
Qiita
2記事!少ない!!
2015年に発表したトーク(public)
www.slideshare.net
www.slideshare.net
www.slideshare.net
www.slideshare.net
4回!ま、まあ...
振り返り
JavaScript一色だなぁ...
ブラウザサイドからNodeJSまで。 ただ、使っているツールや関心の範囲はこの一年でだいぶかわってきたのかなと思う。
フロントエンドツールの開拓、WAFのアーキテクチャ設計、それに関連する各種ライブラリの選定等など、外部モジュールを触るのが多い一年だった。 MVCよくわからんっていう時期から、FluxやReduxを通じてアプリのアーキテクチャを考えていく中で、 単一のライブラリに頼るのも、複数を組み合わせるのもそれなりに模索が必要だと感じているのが年末だった。
2016年の抱負
ツールは揃ってきているけど、いま欲しいものが現状ない。 そういう「何がほしいのか」という部分を自分が適切に理解し、それに即したライブラリを模索・制作していきたいなとは思っている。
年が明けてから、FluxやReduxによって手放そうとしたMVC,DDDを取り戻す方向性を考えている。 技術的にModelとはどういうものか、というより、Model的な考え方をFlux上に載せつつ、効率的に開発できないかと考えている最近。
僕はもともとMVCについての理解が浅かったので、改めて勉強しようかなと思う。
余談
新年早々部屋が半分水浸しになって大変大変つらかったけど、この先は楽しい一年にしていこうとおもったのでした
#gotandajs でトークしてきました
ブログを書くまでがgotandajsだ!ってことで。
gotandajs
五反田や沖縄で JavaScript の勉強する(conpassから引用)会で、AngularJSにFluxとRiotJSを導入したというトークをしてきました。
発表資料
発表について
不足してたなっていう状況を幾つか補足。
- モバイル中心のウェブアプリ(ゲーム)
- JavaScriptを触る人は基本的に僕一人
- 実際にFluxを導入し始めて発表内容の形に持ってくるまで3,4ヶ月くらいかけてる
injector
をRiotJSから参照できるようにするのってどうなの?- 僕一人だから許容してたけど複数人で触るとリスクのほうが高そうなので、ぶっちゃけあんまオススメしない
全体を通して
- 思っていたよりガチで濃ゆい人が集まっていた -- flux, angular, riotを知ってる人が思いの外多くいた -- 他の人のトークも結構濃ゆい話題だった
- Mithrilやreduxといった最近気になっているけど本気で触る余裕がない~なモノとかの話題もあって嬉しい -- トレンドをみんな抑えてる感じで、初回なのにレベル高い
懇親会ネタ
ぱっと思い出せたネタを書き出してみる
- みんな結構、FluxとかReduxとかの設計面で悩んでいる
- Fluxやってると全体でstateを管理したいけど、Reduxみたいに全部管理するのはちょっと
- 程よくComponentとStoreで分散させたい
- ルーターとかどうしてる?
- ReactRouterとか学習コスト高すぎ
- redux-routerは良さそう?
- 最近のライブラリだと何を選ぶ?
- 僕なら初期開発の楽さでAngular
- Vueはすべてがそこそこ良いので安定
- Reactはなんかいろいろめんどくさい、が思想はいい
- Mithrilは
msx-loader
が壊れてて... - などなど...
- テストどうしてる?
- reduxはサンプルをベースに
- fluxとかでロジックはテストし易い
- Reactはテストしやすい...んだろうけど...「「...」」
- Viewのテストのコストが高すぎる
- E2Eでテストしたほうがカバーする範囲広くてリファクタリングとかしやすそう
- 「何」をテストしたいのか? 「ユーザに届ける価値」「どうやってテストすればいいんだー!」
- DIは料理番組
- 下ごしらえ済みの素材を受け取って料理にするイメージ
- だからinjectorをRiotで受け取るのどーなん?って思った
- 静岡アツい
- 次回はG社で
設計の話からビルドシステムの話、他の言語やコミュニティの話、かなり幅広く盛り上がっていた印象
感想
とても楽しい会だった。
なんかみんな似たようなことで悩んでいたり、試そうと思っていたことを試したっていうFBもらえたり、なかなかいい知見を得られたと思う。 コンポーネントのあり方とか、Fluxの設計とかはまだまだ議論の余地もあるだろうし、こういう機会があるのはありがたい。
新しいライブラリも短いサイクルでバンバンでてくるようなJavaScript界隈においてそれぞれが試して意見を交換できる会は貴重だ。
みんなのレベル感も結構近いのでは?と思うくらい懇親会では盛り上がっていたし、本当に楽しかった。
というわけで、大変満足でした。次回も期待します。
お疲れ様でした!
MINILA AIR US67 を購入したのでMac用にカスタマイズしたメモ
商品
Majestouch MINILA Air US67キー 茶軸
設定
caps lock
⇔ctrl
- 鉄板
- [修飾キー設定]
cmd
⇔option
- [修飾キー設定]
caps lock
→cmd
- caps lockなんて要らん
- windows時代の
ctrl
+v|c
の癖が抜けなくてな...
- [ショートカット] 入力ソース/前の入力ソースを選択
cmd
+ESC
- 左手だけで切り替えたいけど大きくブラインドタッチの状態から手を動かしたくないので
所感など
ctrl
+alt
+fn
で接続設定出来るみたいなことが書いてあったけど、結局connect
ボタン使わないと初期設定できなかったESC
⇔~
するかも- キーの差し替えできるの便利
- 押し心地と触り心地が以前使ってたMajestouchと若干違くて新鮮な心地よさがある
指定期間でDOMを出し分けてくれるangular-periodを公開しました
angular-periodとは
AngularJS のDirectiveで、期間を指定するとその 期間前、期間中、期間後でDOMの表示を切り替えてるようにするものです。
例えば、なんかの応募とかで、以下の様なHTMLをテンプレートエンジンやJavaScriptなどを使って出し分けることがある時に便利です。
angularJSを使った一番お手軽なケースとしてはこんなかんじでしょうか。
angular.module("campaign", []) .controller('CampaignCtrl", function () { this.now = new Date().getTime(); this.start = new Date('2015-08-01T00:00:00').getTime(); this.end = new Date('2015-08-31T23:59:59').getTime(); });
<div class="campaign" ng-controller="Campaign as campaign"> <!-- 期間前の表示 --> <div class="form is-previous" ng-if="campaign.now < campaign.start"> <p>○月☓日から応募できます</p> <!-- 期間中の表示 --> <form class="form" ng-if="start <= campaign.now && campaign.now <= campaign.end"> <button type="submit">応募する!</button> </form> <!-- 期間後の表示 --> <div class="form is-after" ng-if"campaign.end < campaign.now"> <p>応募は締め切りました</p> </div> </div>
angular-periodを使えば、以下のように書けます。
angular.module('campaign', ['angularPeriod']);
<div class="campaign" ng-period ng-period-start="'2015-08-01T00:00:00'" ng-period-end ="'2015-08-31T23:59:59'"> <!-- 期間前の表示 --> <div class="form is-previous" ng-period-when="previous"> <p>○月☓日から応募できます</p> <!-- 期間中の表示 --> <form class="form" ng-period-when="during> <button type="submit">応募する!</button> </form> <!-- 期間後の表示 --> <div class="form is-after" ng-period-when="after"> <p>応募は締め切りました</p> </div> </div>
開始と終了を渡すと、その期間の前、中、後のHTMLを選択してDOM Treeに組み込みます。 最も単純なケースではコントローラーすら不要なので、ロジックやテストを大幅に削減できます。
また、angular-periodはリアルタイムな反映及び、setTimeoutの上限値である32bit intを超える値もサポートできるようにしているので、長期にわたる期間であってもある程度は許容されます。
インストール
npm, bowerともに公開しているので必要な方を利用してください。
npm install angular-period
bower install angular-period
日付の指定とパースについて
利用可能な値
上記には文字フォーマットを用いた例を記載しました。 ただ、実際にプログラムする上で文字列だけでは様々な不便なことがあるでしょう。
ngPeriodは Date
オブジェクトに変換可能な値をサポートしています。
具体的には、
- Date
のパース可能な文字列
- Date
オブジェクト
- momentjsなどのDateオブジェクトに渡せるオブジェクト
先ほどの例で、例えばmomentjsを使う場合は以下の様に書けます。
angular.module('campaign', ['angularPeriod']) .controller('CampaignCtrl", function () { this.start = moment('2015-08-01 00:00:00'); this.end = moment('2015-08-31 23:59:59'); });
<body ng-controller="Campaign as campaign"> <div class="campaign" ng-period ng-period-start="campaign.start'" ng-period-end ="campaign.end"> <!-- 期間前の表示 --> <div class="form is-previous" ng-period-when="previous"> <p>○月☓日から応募できます</p> <!-- 期間中の表示 --> <form class="form" ng-period-when="during> <button type="submit">応募する!</button> </form> <!-- 期間後の表示 --> <div class="form is-after" ng-period-when="after"> <p>応募は締め切りました</p> </div> </div> </body>
至ってシンプル。
パースできない値
Dateオブジェクトでパース可能な値はブラウザによって異なります。
パースできない値を渡すと、Dateは Invalid Date
というオブジェクトを返すので、
それをそのままDateとして扱おうとすると、Nanだったり不適切な値になりえます。
困るケースでは、ChromeとSafariで利用可能なDateのフォーマットが異なるという点です。
Chromeは YYYY-MM-DD HH:mm:ss
という値をサポートしていますが、SafariではInvalid Date
が返ってきます。
これは失念すると非常に気づきにくくリスキーで、常にChromeとSafariでの動作確認を要求されるため大変不便です。
angular-periodでは、Invalid Date
になるような値を渡された場合その時点でErrorオブジェクトをthrowするようにはしています。
JavaScriptのDateオブジェクトは非常に複雑かつブラウザ間で挙動が違うので、それを吸収するよりは、すでに実装され安定的に運用されている他のモジュール(momentjsのような)を利用することを推奨します。
まとめ
というわけで結構便利なモジュールを書いたつもりで居るのでどうぞお試しあれ。
node-hariko にクリパラメータによってモックデータを割り振る機能を入れた
欲しかった機能をいれたかったので、 hariko を v1.1.0 に更新しました。
更新内容としては、複数のリクエストをExamplesに設定している時に、リクエストパラメータがマッチするやつを優先的にレスポンスさせるような機能を追加しました。
multipe example
API-Blueprintでは一つのアクションに複数のレスポンスを記載できます。
# GET /messages{?page} + Request /messages (application/json) + Response 200 (application/json) パラメータが無いときは `page=1` としてデータを返す + Body [ /* message arrays */ ] + Request /messages?page=2 (application/json) + Response 200 (application/json) + Body [ /* message arrays */ ] + Request /messages?page=9999 (application/json) + Response 200 (application/json) 存在しないページをしたら空の配列(`[]`)を返す + Body []
モックサーバのレスポンスとの兼ね合い
複数のExampleを定義をした時、リクエストとレスポンスは一つのActionの中に配列で格納されるんだけど、drakov ではキーのマッチングで優先順位を決めてマッチングしてたけど、そんなことよりキーと値が一致したらそいつを優先的に返して欲しい。
上記の例だと
|GET /message|ひとつめ| |GET /message?page=1|ふたつめ| |GET /message?page=2|ふたつめ| |GET /message?page=9999|ふたつめ|
みたいに帰ってきて、9999にリクエストしたら空のレスポンスが帰ってこない!!みたいになる。 いくら、json-outputの機能があるとはいえ、毎回毎回書き換えるのはだるくて仕方ないし、ドキュメント上で明示しておきたい。
クエリパラメータのでマッチングして完全一致したやつを優先的に出力する
node-hariko/resource_spec.js at master · rymizuki/node-hariko · GitHub
こんな感じで。 クエリパラメータの値がMarkdown上で定義されて居て、かつ一致するものがあればそれをレスポンス、 一致するものが無かったら先頭で定義しているものをレスポンスという形にした。
|GET /message|ひとつめ| |GET /message?page=1|ひとつめ| |GET /message?page=2|ふたつめ| |GET /message?page=9999|みっつめ|
を返してくれるようにした。
まとめ
- リクエストとレスポンスを密に連携してよりデバッグしやすい環境を作りました!
todo
- warningsをいまちゃんと出力してないので教えてあげてほしい。
- できれば、コードを示して「どこでwarningsでているのか」をもっとわかりやすくしたい