Reduxでフィールド入力値に対する処理の共通化

はじめに

Reduxでフィールドに入力した値などをstoreに保存する処理をなるべく共通化したいと思ったので、その際の方法をメモします。
※redux-thunkを使っています。

修正前のソースコード

View

<TextField
    id="hoge1"
    value={this.props.something.hoge1}
    onChange={(e) => {
        this.props.setHoge1(e.target.value);
    }}
/>

<TextField
    id="hoge2"
    value={this.props.something.hoge2}
    onChange={(e) => {
        this.props.setHoge2(e.target.value);
    }}
/>

Action

export const setHoge1 = value => dispatch => dispatch({ type: 'CHANGE_HOGE1', value });

export const setHoge2 = value => dispatch => dispatch({ type: 'CHANGE_HOGE2', value });

Reducer

switch (action.type) {
  case 'CHANGE_HOGE1':
    return Object.assign({}, state, { hoge1: action.hoge1 });
  case 'CHANGE_HOGE2':
    return Object.assign({}, state, { hoge1: action.hoge2 });
  default:
    return state;
}

修正後のソースコード

ポイントとしては、
・「SET_PROPERTY」というActionだけを定義するだけで済むようにしました。
・「reducerName」を持たせることで、別のreducerで「SET_PROPERTY」が呼ばれても、対象のReducer以外は影響がないようにしました。
・Reducerはidに応じたプロパティを自動で設定するようにしました。
(画面の項目が増えてもActionとReducerを修正する必要が無くなりました)

View

<TextField
    id="hoge1"
    value={this.props.something.hoge1}
    onChange={(e) => {
        this.props.setProperty(e.target.id, e.target.value);
    }}
/>

<TextField
    id="hoge2"
    value={this.props.something.hoge2}
    onChange={(e) => {
        this.props.setProperty(e.target.id, e.target.value);
    }}
/>

Action

export const setProperty = (id, value) => dispatch => dispatch({ type: 'SET_PROPERTY', id: id, value: value, reducerName: 'hoge' });

Reducer

if (action.reducerName !== 'hoge') return state;
switch (action.type) {
  case 'SET_PROPERTY':
    if (!(action.id in state)) throw `${action.id} not found`;
    return Object.assign({}, state, { [action.id]: action.value });
}