Redux フレームワークは reducers を使用して、アクションに応じてアプリの状態を変更します。
重要な要件は、レデューサーが既存の状態オブジェクトを変更できないことです。新しいオブジェクトを生成する必要があります。
悪い例:
import {
ACTIVATE_LOCATION
} from './actions';
export let ui = (state = [], action) => {
switch (action.type) {
case ACTIVATE_LOCATION:
state.activeLocationId = action.id;
break;
}
return state;
};
良い例:
import {
ACTIVATE_LOCATION
} from './actions';
export let ui = (state = [], action) => {
switch (action.type) {
case ACTIVATE_LOCATION:
state = Object.assign({}, state, {
activeLocationId: action.id
});
break;
}
return state;
};
これは、 Immutable.js の適切な使用例です。
Immutableを使用した良い例
import {
ACTIVATE_LOCATION
} from './actions';
import { Map } from 'immutable';
const initialState = Map({})
export let ui = (state = initialState, action) => {
switch (action.type) {
case ACTIVATE_LOCATION:
return state.set('activeLocationId', action.id);
default:
return state;
}
};
Immutable.jsは、必要に応じて各レデューサーで使用する必要があります。
import {
ACTIVATE_LOCATION
} from './actions';
import Immutable from 'immutable';
export let ui = (state, action) => {
switch (action.type) {
case ACTIVATE_LOCATION:
state = Immutable
.fromJS(state)
.set('activeLocationId', action.id)
.toJS();
break;
}
return state;
};
ただし、この例には多くのオーバーヘッドがあります。reducerアクションが呼び出されるたびに、JavaScriptオブジェクトをImmutableのインスタンスに変換し、結果のオブジェクトを変更してからJavaScriptオブジェクトに戻す必要があります。
より良いアプローチは、初期状態をImmutableのインスタンスにすることです。
import {
ACTIVATE_LOCATION
} from './actions';
import Immutable from 'immutable';
let initialState = Immutable.Map([]);
export let ui = (state = initialState, action) => {
switch (action.type) {
case ACTIVATE_LOCATION:
state = state.set('activeLocationId', action.id);
break;
}
return state;
};
この方法では、初期状態をImmutable
オンスのインスタンスに変換するだけで済みます。次に、各レデューサーはそれをImmutable
のインスタンスとして扱い、Immutable
のインスタンスとして行に渡します。問題は、ビューコンテキストに値を渡す前に、状態全体をJavaScriptにキャストする必要があることです。
レデューサーで複数の状態ミューテーションを実行している場合は、 バッチミューテーション.withMutations
を使用することを検討してください。
物事を簡単にするために、 redux-immutable ライブラリを開発しました。 reduxパッケージの同じ名前の関数と同等のcombineReducers
関数を提供しますが、初期状態とすべてのリデューサーが Immutable.js オブジェクトで動作することを期待しています。
突然変異を起こさずに更新を行う簡単な方法を探している場合、私はライブラリを管理しています: https://github.com/substantial/updeep これは、私の意見では、良い方法ですredux
でそれを行います。
updeep
を使用すると、通常の(凍結された)オブジェクト階層を操作できるため、構造化を行ったり、ログやデバッガー内のオブジェクトを確認したりできます。また、バッチ更新を可能にする強力なAPIも備えています。必要に応じてオブジェクトを複製するため、大規模なデータセットではImmutable.jsほど効率的ではありません。
以下に例を示します(ただし、READMEの内容を確認してください):
import {
ACTIVATE_LOCATION
} from './actions';
import u from 'updeep';
export let ui = (state = [], action) => {
switch (action.type) {
case ACTIVATE_LOCATION:
state = u({ activeLocation: action.id }, state);
break;
}
return state;
};
受け入れられた答えは受け入れられた答えであってはなりません。不変を使用して状態を初期化し、(前述のように)redux-immutablejsを使用する必要があります
const initialState = Immutable.fromJS({}) // or Immutable.Map({})
const store = _createStore(reducers, initialState, compose(
applyMiddleware(...middleware),
window.devToolsExtension ? window.devToolsExtension() : f => f
));
Redux-immutablejsのcomposeReducersを使用するより
追加のヒント:react-router-reduxの使用は非常にうまく機能するため、これを追加する場合は、react-router-reduxのリデューサーを次のように置き換えます。
import Immutable from 'immutable';
import {
UPDATE_LOCATION
} from 'react-router-redux';
let initialState;
initialState = Immutable.fromJS({
location: undefined
});
export default (state = initialState, action) => {
if (action.type === UPDATE_LOCATION) {
return state.merge({
location: action.payload
});
}
return state;
};
これをルートレデューサーにインポートするだけです
これはredux-immutablejsのドキュメントにも記載されています
https://github.com/indexiatech/redux-immutablejs をご覧ください
Redux標準に準拠するcombineReducer
とオプションのcreateReducer
です。