Posted at

Reduxで、reducer内でstateを書き換えると怒られる話

More than 1 year has passed since last update.


初めに

こんな感じでreduxのreducerを書いたら何故かexceptionが吐かれてとても悩んだ。

export default (state: State = INITIAL_STATE, action: ActionType): State => {

switch (action.type) {
case MY_ACTION_NAME: {
const current = state.handlingData;
action.dataArray.forEach((d) => {
current[d.key] = d.data;
});
return {
...state,
handlingData: current,
};
}
default:
return state;
}
};

エラーメッセージはこんな感じ ↓

YellowBox.js:78 Possible Unhandled Promise Rejection (id: 0):

Invariant Violation: A state mutation was detected inside a dispatch, in the path: (state名)


原因

realmを使っていたり非同期にしていたりするせいで何かよくわからないところで変なエラーが起きているんじゃないか、とか余計なことを考えて的外れな調査をしてしまい時間がかかったが、何てことはない。

メッセージ通り、以下のようにreducer内でstateを書き換えていたのが原因だった。

      const current = state.handlingData;

action.dataArray.forEach((d) => {
current[d.key] = d.data; // ← currentがstateの一部なのでこれで書き換わっている
});

ちなみに、console内に出力されるエラーメッセージに以下のリンクが貼られていたお陰で気付くことができた。

http://redux.js.org/docs/Troubleshooting.html#never-mutate-reducer-arguments


対策

上記の部分を以下のように書き換えたら直った。

      const current = { ...state.handlingData };

action.dataArray.forEach((d) => {
current[d.key] = d.data;
});


終わりに


  • 気を付けよう。

  • 公式リファレンスは役に立つ。