私のサービスクラスは、Webサービスを呼び出す前に、私の状態からdataForUpdate
というプロパティを取得する必要があります。現在、私はこれを次のようにしています:
constructor ( public _store: Store<AppState>,
public _APIService:APIService) {
const store$ = this._store.select ('StateReducer');
.../...
let update = this.actions$.filter ( action => action.type==UPDATE )
.do( (action) => this._store.dispatch({type: REDUCER_UPDATING, payload : action.payload }) )
*** GET STATE ***==> .mergeMap ( action => store$.map ( (state : AppState)=> state.dataForUpdate ).distinctUntilChanged(),
(action, dataForUpdate) {
return { type:action.type, payload : {employee:action.payload, dataForUpdate :dataForUpdate } };
})
* AND CALL API *==> .mergeMap ( action =>this._APIService.updateEmployee(action.payload.employee, action.payload.dataForUpdate),
(action, APIResult) => { return { type:REDUCER_UPDATED }})
.share ();
.../...
let all = Observable.merge (update, ....);
all.subscribe ((action:Action) => this._store.dispatch (action));
}
として、angular2-store-example( https://github.com/ngrx/angular2-store-example/blob/master/src/app/users/models/users.ts )を使用していますフォローするガイド。
より良い(よりきれいな)方法が存在するのだろうか?
@ngrx/store
は BehaviorSubject を拡張し、使用できるvalue
プロパティがあります。
this._store.value
それがアプリの現在の状態になり、そこからプロパティ、フィルター、マップなどを選択できます...
更新:
あなたの例の内容を理解するのにしばらくかかりました(:dataForUpdate
の現在の値を取得するには、以下を使用できます:
let x = this._store.value.StateReducer.dataForUpdate;
console.log(x); // => { key: "123" }
バージョン2への更新により、 docs で説明されているようにvalue
が削除されました。
Storeから最新の状態値を同期的にプルするためのAPIは削除されました。代わりに、状態値を取得する必要がある場合は、
subscribe()
が常に同期して実行されることに依存できます。
function getState(store: Store<State>): State {
let state: State;
store.take(1).subscribe(s => state = s);
return state;
}
サブスクリプションチェーンのwithLatestFrom()
またはcombineLatest()
メソッドは、必要なものだけを提供し、Observables + Ngrxの精神に沿っています。
上記のコードのGET STATE .mergeMap()
の代わりに、withLatestFrom()
を使用すると次のようになります。
...
.withLatestFrom(store$, (payload, state) => {
return {payload: payload, stateData: state.data}
} )
...
余談ですが、元の質問のコードはreduxアクションの非同期効果を管理しているように見えます。これはまさに ngrx/effects ライブラリの目的です。ぜひチェックしてみてください。 Effectsの接続が完了すると、非同期reduxアクションを管理するためのコードはずっときれいになります。 Jim Lynchによるこの記事は、私にとっても非常に役に立ちました。 [ngrx/effects]、@ Effect、およびAngularの「ngrx/store」の非同期ミドルウェアの基本2
厳密には質問への直接的な答えではありませんが、ストアから単一の値を取得する方法を探しているこのページを見つけました。
これを実現するために、以下に示すように@ngrx/store
からState
オブジェクトを注入できます。
import { State } from '@ngrx/store';
constructor (private state: State<AppState>) {
let propertyValue = state.getValue().path.to.state.property;
}
state
オブジェクトは、.getValue()
メソッドによってアクセスされるプライベート_value
プロパティに現在の状態を保持します。
@Sasxaからの回答に続いて、@nrgx/store
の新しいバージョン(v5およびv6)で構文が変更されました。基礎となるRxJSライブラリが^ 5.5.0に更新された後、すべてのObservable
インスタンスで使用可能なパイプメソッドがあり、これにより、チェーンを容易にし、サブスクリプションの達成方法を変更できます。
したがって、次のようなことができます。
import { take } from 'rxjs/operators';
store.select('your-state').pipe(take(1)).subscribe(
val => console.log(val)
);
または、厳密にpipe()
演算子を使用します:
import { select } from '@ngrx/store';
import { take } from 'rxjs/operators';
store.pipe(select('your-state'), take(1)).subscribe(
val => console.log(val)
);
AppStateのプロパティである2つのカウンターと2つのリデューサーを持つ状態を持つミニマルなアプリケーションを作成しました。各レデューサーは特定のカウンターにバインドされており、console.log
その値になる各カウンターのオブザーバブルをサブスクライブしました。リデューサー自体も、呼び出されたときにコンソールに書き込みます。
イベントをディスパッチすることで両方のリデューサーを呼び出すボタンがあります。また、2つのカウンターは2つのラベルにバインドされているため、それらの変更は-<p>Counter: {{counter1 | async}}</p>
と表示されます。
各カウンターをレデューサーにマッピングするには、StoreModule.forRoot({ counter1: Reducer1, counter2 : Reducer2 })
を使用します
import { Component, NgModule } from '@angular/core';
import { Store, Action, StoreModule } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import { BrowserModule } from '@angular/platform-browser';
interface AppState {
counter1 : number;
counter2 : number;
}
export function Reducer1(counter : number = 0, action : Action) {
console.log(`Called Reducer1: counter=${counter}`);
return counter + 1;
}
export function Reducer2(counter : number = 0, action : Action) {
console.log(`Called Reducer2: counter=${counter}`);
return counter + 2;
}
@Component({
selector: 'app-root',
template: `<p>Counter: {{counter1 | async}}</p>
<p>Counter: {{counter2 | async}}</p>
<button (click)='increment()'>Increment</button>`
})
export class AppComponent {
title = 'app';
counter1 : Observable<number>;
counter2 : Observable<number>;
constructor(private store : Store<AppState>) {
this.counter1 = this.store.select('counter1');
this.counter2 = this.store.select('counter2');
this.counter1.subscribe(x => console.log(`Subscribe event for counter1 fired: counter=${x}`));
this.counter2.subscribe(x => console.log(`Subscribe event for counter2 fired: counter=${x}`));
}
increment() {
this.store.dispatch({type:'foo'});
}
}
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
StoreModule.forRoot({ counter1: Reducer1, counter2 : Reducer2 })
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
ngStoreのStateクラスはBehaviorSubjectであるため、これを注入し、そのvalueプロパティを使用して最新の値を取得できます。
constructor(private state:State<YourState>...) {
}
someMethod() {
// WHAT'S MORE: you can use your selector directly on it!
let v = yourSelector(this.state.value);
}