ReduxとObject.assignの罠

Reduxと伝統的Fluxの大きな違いの一つはStore層の扱いかたである。

FluxではすべてのStoreを定義する必要があったのに対し、ReduxではStoreはアプリケーション全体に一つ存在するのみで、reducerと呼ばれる関数を使って、間接的に変更していく。これによって、冗長になりがちであったStoreを書かなくていい分、全体のコード量が減る(まさにreducer)。

reducerは通常のJavaScript関数であり、ステートとアクションを受け取って、アクションのタイプごとにステートをアップデートして返す、という振る舞いをする。

export default function sugoiReducer(state, action) {

  switch (action.type) {
  case 'SUGOI_ACTION_TYPE':
    return Object.assign({}, state, { change: 'value' });
  default:
    return state;
  }
}

その際に、なぜかは知らないがステートを変更するのではなく、新しいオブジェクトを作って返せ、問いうルールがある。上記のコードで言えば「Object.assign」を使わないといけないのだ。これを

export default function sugoiReducer(state, action) {

  switch (action.type) {
  case 'SUGOI_ACTION_TYPE':
    state.change = 'value';
    return state;
  default:
    return state;
  }
}

とすると、ステートの値自体は変更され保持されるが、Reactのコンポーネントには反映されないことになる。ちゃんと理解してないがイミュータブルなオブジェクトがなにかしているんだろう。今度調べたい。

もう一つのハマリどころとしてあったのが、Object.assign関数それ自体である。BabelでトランスパイルすればこちらもよろしくES5に変換してくれるんだろう、くらいに思っていたが、この関数はそのまま出力されるようだ。これを解決するにはbabel-plugin-transform-object-assignをプラグインとして入れる必要がある。

今回はCIで回してるphantomJSがこけてくれたのですぐに気づくことができたが、Chromeだけで開発しているとこういうのが怖いなあと思った。