すべての開発者は、状態管理がかなり複雑なものであることを知っています。 特に大規模なアプリケーションでは、どこでいつ変更されたかを追跡するのは悪夢です。
Angularの世界には、状態管理の複雑さ、痛み、脆弱性を軽減できるソリューションがいくつかあります。
最も人気のある2つのソリューションは、主にReduxに触発されたngrx/store
とObservable data servicesです。
個人的に、私はReduxが本当に好きで、定型コードのすべての行がかかります。 しかし、残念なことに、一部の人は私に反対するかもしれませんし、Reduxは彼らのアプリケーションには特に当てはまりません。
したがって、状態管理の問題を解決する上でMobxがどのように役立つかを説明することにしました。 その考えは、ReduxとMobxの2つの世界を結合することです。
それでは、Redux耐性、Rx + ngrxのパワー、およびMobx状態管理機能を取り上げましょう。 この組み合わせにより、非同期パイプをOnPush
戦略と組み合わせて使用して、最高のパフォーマンスを実現できます。
始める前に、MobxとAngularについて十分な知識があることを理解してください。
簡単にするために、従来のtuduアプリケーションを作成します。 さあ、始めましょうか?
横
単一の責任の原則を遵守したいので、フィルター用のフィルターを作成します(必要に応じて、それらを1つに結合できます)。
フィルターサイドを作成しましょう。
import { Injectable } from '@angular/core'; import { action, observable} from 'mobx'; export type TodosFilter = 'SHOW_ALL' | 'SHOW_COMPLETED' | 'SHOW_ACTIVE'; @Injectable() export class TodosFilterStore { @observable filter = 'SHOW_ALL'; @action setFilter(filter: TodosFilter) { this.filter = filter; } }
dudushkiに側面を追加します。
export class Todo { completed = false; title : string; constructor( { title, completed = false } ) { this.completed = completed; this.title = title; } } @Injectable() export class TodosStore { @observable todos: Todo[] = [new Todo({ title: 'Learn Mobx' })]; constructor( private _todosFilter: TodosFilterStore ) {} @action addTodo( { title } : Partial<Todo> ) { this.todos = [...this.todos, new Todo({ title })] } @computed get filteredTodos() { switch( this._todosFilter.filter ) { case 'SHOW_ALL': return this.todos; case 'SHOW_COMPLETED': return this.todos.filter(t => t.completed); case 'SHOW_ACTIVE': return this.todos.filter(t => !t.completed); } } }
Mobxに慣れている場合、上記のコードは非常に簡単に思えます。
常に、 @action
デコレータを使用して@action
。 Redux以来知られている「状態を直接変更しない」という概念を遵守するのに役立ちます。 Mobxドックの発言:
厳格モードでは、アクション以外で状態を変更することはできません。
RxJS ブリッジ
RxJSの素晴らしい点の1つは、任意のデータソースをRxJS Observableに変換する機能です。 この場合、Mobxからcomputed
関数を使用して状態の変化をリッスンし、Observableのサブスクライバーに渡します。
import { Observable } from 'rxjs/Observable'; import { computed } from 'mobx'; export function fromMobx<T>( expression: () => T ) : Observable<T> { return new Observable(observer => { const computedValue = computed(expression); const disposer = computedValue.observe(changes => { observer.next(changes.newValue); }, true); return () => { disposer && disposer(); } }); }
Rx computed
は、 BehaviorSubject
ような何かがdistinctUntilChanged()
と混合されdistinctUntilChanged()
式に変更(参照による変更)が発生するたびに、コールバックが実行され、新しい値がサブスクライバーに渡されます。 これで、MobxとRxの間にブリッジができました。
成分
Input()
を受け取り、選択されたときにイベントを発生するコンポーネントを作成しましょう。
ここでは、 onPush
戦略を使用して変更を識別することに注意してください。
@Component({ selector: 'app-todo', template: ` <input type="checkbox" (change)="complete.emit(todo)" [checked]="todo.completed"> {{todo.title}} `, changeDetection: ChangeDetectionStrategy.OnPush }) export class TodoComponent { @Input() todo: Todo; @Output() complete = new EventEmitter(); }
ヒキガエルリストコンポーネント
Input()
を受け取り、何かが選択されたときにイベントを発行するヒキガエルリストコンポーネントを作成しましょう。
ここでは、 onPush
戦略を使用して変更を識別することに注意してください。
@Component({ selector: 'app-todos', template: ` <ul> <li *ngFor="let todo of todos"> <app-todo [todo]="todo" (complete)="complete.emit($event)"> </app-todo> </li> </ul> `, changeDetection: ChangeDetectionStrategy.OnPush }) export class TodosComponent { @Input() todos: Todo[] = []; @Output() complete = new EventEmitter(); }
プラグインページコンポーネント
@Component({ selector: 'app-todos-page', template: ` <button (click)="addTodo()">Add todo</button> <app-todos [todos]="todos | async" (complete)="complete($event)"> </app-todos> ` }) export class TodosPageComponent { todos : Observable<Todo[]>; constructor( private _todosStore: TodosStore ) { } ngOnInit() { this.todos = fromMobx(() => this._todosStore.filteredTodos); } addTodo() { this._todosStore.addTodo({ title: `Todo ${makeid()}` }); } }
ngrx/store
で作業した場合は、 ngrx/store
だ気分になるでしょう。 todos
プロパティはRx Observableであり、ストアのfilteredTodos
プロパティが変更filteredTodos
ときにのみ機能します。
todos
プロパティは、 filter
またはストアのtodos
プロパティでクリーンな変更が発生した場合に変更をトリガーするcomputed
値です。
そしてもちろん、 combineLatest()
、 take()
などのようなすべてのRxパンを取得します。これは現在Rxストリームであるためです。
以上です。 これが既製の例です。
あなたはこの小さなコンセプトが好きだったと思う、あなたが興味を持っていたと思います。
PMのブラックホールに気づいた