成果物
目的
Redux
とES6
への入門。
React.jsを(ようやく)触る機会が出て、情報量の多いFluxxor
とCoffeeScript
で入門してた。
いろいろ情報を集めると、flummox
が人気!!みたいなのを見て、覗いてみたら4.0 will likely be the last major release. Use Redux instead. It's really great.
って書いてあってRedux
を触ってみることにした。exampleとawesome-reduxを眺めたらどれも当たり前のようにES6
で書かれていて、合わせて入門することにした。
Redux概要
まだかなり理解が怪しいんだけど、以下の図がイメージしやすかった。
André Staltz - Unidirectional User Interface Architecturesより
- Singleton Store: アプリケーションのステートは単一のストアで管理する
- provider: ストア内のステートとReactなどのviewとのインターフェース
- Actions: ユーザによって発生するイベント
- Reducers: 前回のステートとアクションより新しいステートを計算してストアに渡す、純粋な関数
Action
やReducer
が純粋な関数のため、状態変異が予測しやすくなるというのが大きな特徴の一つなよう。
provider
ストアを作ってproviderに渡してやる。 - index.js
const store = configureStore(); React.render( <Provider store={store}> {() => <App />} </Provider>, document.getElementById('content') );
connect
で以下のようにコンポーネントにに接続することでコンポーネントのprops
、この場合CommentBox
のprops
にステートとアクションが渡される。
- containers/app.js
function mapStateToProps(state) { return { comments : state.comments }; } function mapDispatchToProps(dispatch) { return bindActionCreators(commentActions, dispatch); } export default connect( mapStateToProps, mapDispatchToProps )(CommentBox);
サンプルではcontainers
なるディレクトリがあって、なんだ?って思ったら以下に書いてあった。
- contaniners = Smart Components
- reduxやactionsをimportしている
- components = Dumb Components
- reduxやactionsをimportしていない。
- 必要なモノは親から全てprops経由で受け取っている
actions
アクションは以下のように書いて、bindActionCreators
でバインドしてやることでreducer
に配送される。
原則としてAPI叩いたりするのはaction
回りでやって、reducer
は前回ステートとアクションから次ステートを計算することに撤するっぽい。
- actions/comment.js
export const SUBMIT_COMMENT = 'SUBMIT_COMMENT' export const RECIEVE_COMMENTS = 'RECIEVE_COMMENTS' export function submitComment(comment) { return { type: SUBMIT_COMMENT, comment }; } export function recieveComments(comments) { return { type: RECIEVE_COMMENTS, comments }; }
- containers/app.js
function mapDispatchToProps(dispatch) { return bindActionCreators(commentActions, dispatch); } export default connect( mapStateToProps, mapDispatchToProps )(CommentBox);
reducer
前回ステートとアクションより次のステートを計算してストアに渡す。 ここでAPIたたいたり、ラウタ―遷移したりしないこと。
- reducers/comment.js
import * as commentActions from '../actions/comment'; export default function comment(state={comments : []}, action) { switch(action.type){ case commentActions.SUBMIT_COMMENT: let comments = state.comments.concat([action.comment]); return {comments}; case commentActions.RECIEVE_COMMENTS: return {comments : action.comments}; default: return state; } }
下記のようにreducer
からcreateStoreWithMiddleware
またはcreateStore
でストアを生成する。
- store/configStore.js
import {createStore, applyMiddleware} from 'redux'; import comment from '../reducers/comment' import thunk from 'redux-thunk'; import createLogger from 'redux-logger'; export default function configureStore() { const logger = createLogger(); const createStoreWithMiddleware = applyMiddleware( thunk, logger )(createStore); const store = createStoreWithMiddleware(comment); return store; }
Middleware
最初の図とReducer
のところで出てきたけどRedux
にはMiddleware
って概念があるらしく、dispatchする前、または、した後に任意の処理を追加することができるらしい。
今回はRedux-logger
とRedux-thunk
というミドルウェアを使用している。
ミドルウェアを使用する場合はapplyMiddleware
で適用してやる。
- store/configStore.js
export default function configureStore() { const logger = createLogger(); const createStoreWithMiddleware = applyMiddleware( thunk, logger )(createStore); const store = createStoreWithMiddleware(comment); return store; }
例えばRedux-logger
を使用すると、下図のように前回ステートの値と発生したアクション、それにより計算された次ステートが分かりやすい形でログに吐かれる。
Redux-thunk
を使用すると”特定の条件を満たす場合にdispatch”、”非同期処理の前後でdispatch”などが可能となる。
この辺も怪しいので詳しくは以下を見るといいと思う。
ES6について
初めて書いたんだけどアローファンクションとか拡張オブジェクトリテラルとかのおかげか結構すんなり入れた。これからバンバン書いていきたい。
console.log "hoge"
みたいに()と;をよく忘れるけど・・。