undefined

bokuweb.me

ReduxとES6でReact.jsのチュートリアルの写経

成果物

github.com

目的

ReduxES6への入門。

React.jsを(ようやく)触る機会が出て、情報量の多いFluxxorCoffeeScriptで入門してた。 いろいろ情報を集めると、flummoxが人気!!みたいなのを見て、覗いてみたら4.0 will likely be the last major release. Use Redux instead. It's really great.って書いてあってReduxを触ってみることにした。exampleとawesome-reduxを眺めたらどれも当たり前のようにES6で書かれていて、合わせて入門することにした。

Redux概要

まだかなり理解が怪しいんだけど、以下の図がイメージしやすかった。

f:id:bokuweb:20151002213504j:plain André Staltz - Unidirectional User Interface Architecturesより

  • Singleton Store: アプリケーションのステートは単一のストアで管理する
  • provider: ストア内のステートとReactなどのviewとのインターフェース
  • Actions: ユーザによって発生するイベント
  • Reducers: 前回のステートとアクションより新しいステートを計算してストアに渡す、純粋な関数

ActionReducerが純粋な関数のため、状態変異が予測しやすくなるというのが大きな特徴の一つなよう。

provider

ストアを作ってproviderに渡してやる。 - index.js

const store = configureStore();

React.render(
  <Provider store={store}>
    {() => <App />}
  </Provider>,
  document.getElementById('content')
);

connectで以下のようにコンポーネントにに接続することでコンポーネントのprops、この場合CommentBoxpropsにステートとアクションが渡される。

  • containers/app.js
function mapStateToProps(state)  {
  return {
    comments : state.comments
  };
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators(commentActions, dispatch);
}

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(CommentBox);

サンプルではcontainersなるディレクトリがあって、なんだ?って思ったら以下に書いてあった。

yukidarake.hateblo.jp

  • 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-loggerRedux-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を使用すると、下図のように前回ステートの値と発生したアクション、それにより計算された次ステートが分かりやすい形でログに吐かれる。

f:id:bokuweb:20151002213539j:plain

Redux-thunkを使用すると”特定の条件を満たす場合にdispatch”、”非同期処理の前後でdispatch”などが可能となる。 この辺も怪しいので詳しくは以下を見るといいと思う。

github.com

Async Actions | Redux

ES6について

初めて書いたんだけどアローファンクションとか拡張オブジェクトリテラルとかのおかげか結構すんなり入れた。これからバンバン書いていきたい。 console.log "hoge"みたいに()と;をよく忘れるけど・・。

参考記事

amagitakayosi.hatenablog.com

fluxフレームワークreduxについてドキュメントを読んだメモ - fukajun

yukidarake.hateblo.jp

staltz.com