前回記事はこちら
引続き、angular-redux/storeの使い方を学んでいきます。今回はReducer
を分割する方法について。
バージョン情報
Angular + Reduxの環境を使います
Angular: 5.2.9
angular-redux/store: 7.1.1
Node: 8.1.4
typescript: 2.5.3
webpack: 3.11.0
環境構築
Angular + Redux環境の構築方法について
angular-cliでAngularプロジェクトを作成
angular-redux/store インストール
flux-standard-action インストール
npm install -g @angular/cli ng new [適当なAngularのプロジェクト名] cd [適当なAngularのプロジェクト名] npm install redux --save @angular-redux/store npm install redux --save flux-standard-action
サンプルアプリケーションについて
仮想通貨取引所のビットフライヤーとコインチェックのビットコイン価格を、WebAPIから取得して画面に表示するアプリケーションを例に説明します。
アプリケーションの構造
👇は、Reducer分割前のサンプルアプリケーションの図となります。ReducerがrootReducer
のひとつしかなく、今後規模を拡大していくにあたって問題になりそうなので、分割します。
Stateの構造
本サンプルアプリケーションのState
は、3層にネストされていて、👇画像の構造になっています。Stateの2層目が2つに分かれているので、Reducerについても、(rootReducerも含めて)3つに分割します。
Stateのソースコード
Stateのソースコードについても載せておきます。
src/state/root/store.ts
:
import { BitflyerTickerModel } from '../bitflyer-ticker/bitflyer-ticker.model'; import { CoincheckTickerModel } from '../coincheck-ticker/coincheck-ticker.model'; export interface IAppState { bitflyerTicker: BitflyerTickerModel; coincheckTicker: CoincheckTickerModel; } export const INITIAL_STATE: IAppState = { bitflyerTicker: null, coincheckTicker: null, };
Reducerを分割する
ReduxのcombineReducers
を使って、rootReducer
を3つに分割します。
coincheckTickerReducer
bitflyerTickerReducer
rootReducer
分割前のReducer
分割前のReducerは、rootReducer
一つです。
rootReducer
src/app/state/root/reducer.ts
:
import { IAppState } from './store'; import { Action, combineReducers } from 'redux'; import { BitflyerTickerActions, BitflyerTickerAction } from '../bitflyer-ticker/bitflyer-ticker.action'; import { CoincheckTickerActions, CoincheckTickerAction } from '../coincheck-ticker/coincheck-ticker.action'; export function rootReducer( lastState: IAppState, action: Action ): IAppState { switch (action.type) { case BitflyerTickerActions.BITFLYER_SET_TICKER: return { bitflyerTicker: (action as BitflyerTickerAction).payload, coincheckTicker: lastState.coincheckTicker }; case CoincheckTickerActions.COINCHECK_SET_TICKER: return { bitflyerTicker: lastState.bitflyerTicker, coincheckTicker: (action as CoincheckTickerAction).payload }; default: return lastState; } }
分割後のReducer
rootReducer
を3つに分割しました。
coincheckTickerReducer
bitflyerTickerReducer
rootReducer
coincheckTickerReducer
分割した結果、StateのcoincheckTicker
部分のみを担当するReducerになりました。
src/state/coincheck-ticker/coincheck-ticker.reducer.ts
:
import { Action } from 'redux'; import { CoincheckTickerActions, CoincheckTickerAction } from '../coincheck-ticker/coincheck-ticker.action'; import { CoincheckTickerModel } from './coincheck-ticker.model'; export function coincheckTickerReducer( lastState: CoincheckTickerModel = null, action: Action ): CoincheckTickerModel { switch (action.type) { case CoincheckTickerActions.COINCHECK_SET_TICKER: return (action as CoincheckTickerAction).payload; default: return lastState; } }
bitflyerTickerReducer
StateのbitflyerTicker
部分のみを担当するReducerになっています。
src/state/bitflyer-ticker/bitflyer-ticker.reducer.ts
:
import { Action } from 'redux'; import { BitflyerTickerActions, BitflyerTickerAction } from '../bitflyer-ticker/bitflyer-ticker.action'; import { BitflyerTickerModel } from './bitflyer-ticker.model'; export function bitflyerTickerReducer( lastState: BitflyerTickerModel = null, action: Action ): BitflyerTickerModel { switch (action.type) { case BitflyerTickerActions.BITFLYER_SET_TICKER: return (action as BitflyerTickerAction).payload; default: return lastState; } }
rootReducer
combineReducers
でbitflyerTickerReducer
とcoincheckTickerReducer
を結合しています。
src/app/state/root/reducer.ts
:
import { IAppState } from './store'; import { combineReducers } from 'redux'; import { bitflyerTickerReducer } from '../bitflyer-ticker/bitflyer-ticker.reducer'; import { coincheckTickerReducer } from '../coincheck-ticker/coincheck-ticker.reducer'; export const rootReducer = combineReducers<IAppState>({ bitflyerTicker: bitflyerTickerReducer, coincheckTicker: coincheckTickerReducer, });