はじめに
Reactではなく、AngularからReduxに入門するのは茨の道かと思いますが、やっていきます。 今回はReduxを1サイクル回して、配列を更新してコンポーネントで値を取得するところまでやりました。
開発環境
Angular: 5.2.3
angular-redux/store: 7.1.0
TypeScript: 2.5.3
angular/cli: 1.6.5
OS: darwin x64
Node: 8.1.4
Angular + Redux環境構築手順
まず、Angular CLIを使用してAngularプロジェクトを作成します。
# Install Angular CLI npm install -g @angular/cli # Use it to spin up a new app. ng new [適当なAngularのプロジェクト名] cd [適当なAngularのプロジェクト名]
angular-redux/store
ライブラリをインストール
npm install redux --save @angular-redux/store
flux-standard-action
もインストール
npm install redux --save flux-standard-action
これで環境構築は完了です🎉🎉🎉
コード解説
続いて、コードについて解説していきます。
ReduxをAngularに接続する
まず、app.module.ts
でRedux Storeの読み込みを行います。
src/app/app.module.ts
:
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { NgReduxModule, NgRedux } from '@angular-redux/store'; import { IAppState, INITIAL_STATE } from '../../state/store'; import { TetrisActions } from '../../state/actions'; import { Store, createStore } from 'redux'; import { rootReducer } from '../../state/reducer'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, NgReduxModule, ], providers: [ TetrisActions, ], bootstrap: [AppComponent] }) export class AppModule { constructor(ngRedux: NgRedux<IAppState>) { ngRedux.configureStore(rootReducer, INITIAL_STATE); } }
👆のコードで行なっていること
NgReduxModule
をアプリケーションにインポート- Actionの一つである
TetrisActions
をDIできるようにproviders:
に設定 - Redux Storeを
ngRedux.configureStore
でAngularに接続
Storeの作成
続いてStoreで、State(状態)のプロパティとStateの初期状態での値を設定しています。
今回の例では、board: number[][]
の値を更新します。
src/state/store.ts
:
import { Action } from 'redux'; import { TetrisActions, InitBoardAction } from '../state/actions'; export interface IAppState { board: number[][]; lose: boolean; current: number[][]; currentX: number; currentY: number; } export const INITIAL_STATE: IAppState = { board: null, lose: false, current: null, currentX: null, currentY: null };
Actionの作成
src/state/actions.ts
:
import { Injectable } from '@angular/core'; import { Action } from 'redux'; import { FluxStandardAction } from 'flux-standard-action'; import { dispatch, NgRedux } from '@angular-redux/store'; import { IAppState } from './store'; export type InitBoardAction = FluxStandardAction<number[][], void>; @Injectable() export class TetrisActions { static readonly INIT_BOARD = 'INIT_BOARD'; callInitBoard = (): void => { // 2次元配列に0を代入する const board = Array.from(new Array(20), () => new Array(10).fill(0)); this.initBoard(board); } @dispatch() initBoard = (board: number[][]): InitBoardAction => ({ type: TetrisActions.INIT_BOARD, payload: board, meta: undefined }) }
actions.ts
では、callInitBoard()
で2次元配列board
の全要素に0を設定した後、
initBoard()
を呼び出してActionをディスパッチしています。
Actionのディスパッチには、@dispatch()
デコレータを使用していて、
InitBoardAction
の定義には、環境構築時にインストールしたflux-standard-action
を使用しています。
Reducerの作成
src/state/reducer.ts
:
import { IAppState } from './store'; import { Action } from 'redux'; import { TetrisActions, InitBoardAction } from './actions'; export function rootReducer( lastState: IAppState, action: Action ): IAppState { switch (action.type) { case TetrisActions.INIT_BOARD: return { board: (action as InitBoardAction).payload, lose: lastState.lose, current: lastState.current, currentX: lastState.currentX, currentY: lastState.currentY }; default: return lastState; } }
reducer.ts
では、アクションから取得した配列の値をStateのboard
プロパティに設定した後、stateを返す処理を行なっています。
コンポーネント側でStateを取得する
最後にコンポーネントで現在のboard[][]
の値を取得して、出力します。
NgRedux Store
では、StoreからObservable
として値をselect(選択)
することによって、最新の値取得を実現しています。
src/app/app.component.ts
:
import { Component, ViewChild, AfterViewInit, OnInit, OnDestroy } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { Subscription } from 'rxjs/Subscription'; import 'rxjs/add/observable/fromEvent'; import { select, NgRedux } from '@angular-redux/store'; import { TetrisActions } from '../../state/actions'; import { IAppState } from '../../state/store'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent implements OnInit, OnDestroy { @select() readonly board$: Observable<number[][]>; private subscription: Subscription; constructor(private tetrisAction: TetrisActions) { // boardの新しい値を受け取る this.subscription = this.board$.subscribe(console.log); } ngOnDestroy() { this.subscription.unsubscribe(); } ngOnInit() { // アクション呼び出し this.tetrisAction.callInitBoard(); } }
app.component.ts
では、👇2つの処理を行なっています。
ngOnInit()
でアクションのcallInitBoard()
呼び出し@select
デコレーターを使用することで、board[][]
の最新の値を取得し、console.log
で出力
👆👆👆のコードを全部書いた時点でアプリを動作させると、値が更新された状態の2次元配列board[][]
が出力されているはずです。
関連サイト
Angular + Reduxの公式による解説については下記サイトを参照してください。
store/intro-tutorial.md at master · angular-redux/store · GitHub