Slide 1

Slide 1 text

NgRx v6 Angularでの状態管理

Slide 2

Slide 2 text

新福 宜侑 ng-fukuoka organizer Onsen UI collaborator @puku0x

Slide 3

Slide 3 text

@puku0x Angular 主にGoogleが開発するフロントエンドフレームワーク フルスタックなフレームワーク 状態管理の方法だけ公式で提供されていない (AngularにはRxJSがある...あとはわかるよね?的な)

Slide 4

Slide 4 text

@puku0x 状態管理 各コンポーネントでバラバラに状態を管理していると アプリケーションが大きくなったときに死ぬ 何かしらの仕組みが必要

Slide 5

Slide 5 text

Redux Reducer + Flux

Slide 6

Slide 6 text

@puku0x Redux 状態は一個のオブジェクト 状態は読み取り専用 状態は純粋な関数で変更される http://slides.com/jenyaterpil/redux-from-twitter-hype-to-production

Slide 7

Slide 7 text

NgRx Reactive Extensions for Angular

Slide 8

Slide 8 text

@puku0x NgRx RxJSベースのRedux ● Store ● Action ● Reducer ● Effects $ ng new my-app $ cd my-app $ npm install @ngrx/store $ npm install @ngrx/effects

Slide 9

Slide 9 text

@puku0x NgRx v6 RxJS v6対応 Pipeable operatorの利用(select & ofType) Angular CLI v6の `ng add` & `ng update` 対応

Slide 10

Slide 10 text

Store 状態・データの置き場 export interface State { todos: Todo[]; loading: boolean; } export const initialState: State { todos: [], loading: false, });

Slide 11

Slide 11 text

Action イベント export enum TodoActionTypes { CreateTodo = '[Todo] Create', CreateTodoSuccess = '[Todo] Create Success', } export class CreateTodo implements Action { readonly type = TodoActionTypes.CreateTodo; constructor(public payload: { todo: Todo } ) {} }

Slide 12

Slide 12 text

export function reducer(state = initialState, action: TodoAction): State { switch (action.type) { case TodoActionTypes.CreateTodo: { return { ...state, loading: true }; } default: { return state; } } } Reducer

Slide 13

Slide 13 text

@Effect() createTodo$: Observable = this.actions$.pipe( ofType(TodoActionTypes.CreateTodo), concatMap(action => { const { todo } = action.payload; return this.todoService.create(todo).pipe( map(result => new CreateTodoSuccess({ todo: result })), catchError(error => of(new CreateTodoFail({ error }))) ); }) ); Effects

Slide 14

Slide 14 text

@puku0x 詳しくはWebで

Slide 15

Slide 15 text

@puku0x サンプルプログラム https://stackblitz.com/edit/ngrx-todo-v1

Slide 16

Slide 16 text

思ったより複雑かも...

Slide 17

Slide 17 text

@puku0x Facade Pattern https://medium.com/@thomasburleson_11450/ngrx-facades-better-state-management-82a04b9a1e39

Slide 18

Slide 18 text

export class TodoFacade { loading$ = this.store.pipe(select(todoQuery.getLoading)); todos$ = this.store.pipe(select(todoQuery.getTodos)); createSuccess$ = this.actions$.pipe(ofType(...)); create(todo: Todo) { this.store.dispatch(new CreateTodo({ todo })); } } Facade

Slide 19

Slide 19 text

@puku0x サンプルプログラム https://stackblitz.com/edit/ngrx-todo-v2

Slide 20

Slide 20 text

ボイラープレート多い問題

Slide 21

Slide 21 text

@puku0x NgRx helpers @ngrx/schematics @ngrx/entity ngrx-data

Slide 22

Slide 22 text

$ npm install @ngrx/schematics $ ng config cli.defaultCollection @ngrx/schematics $ ng g action todo $ ng g reducer @ngrx/schematics

Slide 23

Slide 23 text

import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity'; export interface State extends EntityState { } export const adapter: EntityAdapter = createEntityAdapter(); export const initialState: State = adapter.getInitialState({ }); export function reducer(state = initialState, action: TodoActions): State { switch (action.type) { case TodoActionTypes.CreateTodoSuccess: { return adapter.addOne(action.payload.todo, { ...state, loading: false }); } } @ngrx/entity

Slide 24

Slide 24 text

export const entityMetadata: EntityMetadataMap = { Todo: {}, }; @NgModule({ imports: [ NgrxDataModule.forRoot({ entityMetadata }) ], }) export class AppStoreModule { } ngrx-data

Slide 25

Slide 25 text

@puku0x サンプルプログラム https://stackblitz.com/edit/ngrx-data-todo-v1

Slide 26

Slide 26 text

@puku0x まとめ NgRx v6からPipeable operator使うようになったので移行推奨 Facadeパターンよさそう ボイラープレートの削減は ngrx-data に期待(v7で統合される...?)

Slide 27

Slide 27 text

Thank you! @puku0x ng-fukuoka organizer