前章とは違い、本章はとても簡単で、ちょっとした変更を行うだけです。
まず、コードベースにImmutable JSを追加します。Immutableはオブジェクトを変更(mutating)することなしに扱うためのライブラリです。例えば以下のようにする代わりに:
const obj = { a: 1 };
obj.a = 2; // Mutates `obj`こうすることができます:
const obj = Immutable.Map({ a: 1 });
obj.set('a', 2); // Returns a new object without mutating `obj`このアプローチは関数型プログラミングのパラダイムに則ったもので、Reduxとの相性がとても良くなっています。実際、reducer関数は引数として渡される状態を変更しない、純粋な関数でなければならず、状態オブジェクトを新しく作って返すようになっています。それではImmutableを使い、このやり方を強制してみましょう。
yarn add immutableを実行します。
このコードベースではMapを使うのですが、ESLintとAirbnbの設定はクラス以外に大文字の名前を使うと警告を出します。package.jsonのeslintConfigに以下を追加します:
"rules": {
"new-cap": [
2,
{
"capIsNewExceptions": [
"Map",
"List"
]
}
]
}これはMapとList(この2つのImmutableなオブジェクトはずっと使うことになります)を例外扱いするようESLintルールを変更するものです。この冗長なJSONフォーマットはYarn/NPMによって自動的に行われるもので、残念ながらコンパクトにはできません。
それはさておき、Immutableに戻りましょう:
dog-reducer.jsを以下のように修正します:
import Immutable from 'immutable';
import { MAKE_BARK } from '../actions/dog-actions';
const initialState = Immutable.Map({
hasBarked: false,
});
const dogReducer = (state = initialState, action) => {
switch (action.type) {
case MAKE_BARK:
return state.set('hasBarked', action.payload);
default:
return state;
}
};
export default dogReducer;初期状態はImmutableのMapを使って作られます。そして新しい状態は、それ以前の状態を変更することのないset()を使って作られるようになります。
containers/bark-message.jsのmapStateToProps関数を、.hasBarkedの代わりに.get('hasBarked')を使うよう修正します:
const mapStateToProps = state => ({
message: state.dog.get('hasBarked') ? 'The dog barked' : 'The dog did not bark',
});アプリケーションは以前と同様の振る舞いをするはずです。
注意: BabelがImmutableについて100KB制限を超えていると警告する場合, package.jsonのbabelのところに"compact": falseを追加します。
上記のコード片を見ると分かる通り、状態オブジェクトは素のオブジェクト属性dogを持っており、イミュータブルではありません。これはこれで構わないのですが、イミュータブルオブジェクトしか扱いたくない場合、ReduxのcombineReducers関数を置き換えるため、redux-immutableパッケージをインストールできます。
オプション:
yarn add redux-immutableを実行します。app.jsxにあるcombineReducers関数をredux-immutableからimportしたものに置き換えます。bark-message.jsのstate.dog.get('hasBarked')をstate.getIn(['dog', 'hasBarked'])に置き換えます。
アプリにアクションを加えていくにつれて、同じボイラープレートを何度も書き加えていくことになります。redux-actionsパッケージを使えば、ボイラープレートのコードを減らしてくれます。dog-actions.jsファイルをredux-actionsで簡潔に書き換えることができます。
import { createAction } from 'redux-actions';
export const MAKE_BARK = 'MAKE_BARK';
export const makeBark = createAction(MAKE_BARK, () => true);redux-actionsは先ほど実装したようなアクションであるFlux Standard Actionモデルを実装したもので、このモデルに従っていればredux-actionsはシームレスに導入できます。
yarn add redux-actionsを忘れずに実行します。
(原文: 10 - Immutable JS and Redux Improvements)