我的服务类在调用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)作为指导。
我想知道是否存在更好(更清洁)的方式?
答案 0 :(得分:53)
@ngrx/store
扩展BehaviorSubject,并且您可以使用value
属性。
this._store.value
这将是您应用的当前状态,从那里您可以选择属性,过滤器,地图等......
<强>更新强>
我花了一些时间来确定你的例子中的内容(:要获得dataForUpdate
的当前值,你可以使用:
let x = this._store.value.StateReducer.dataForUpdate;
console.log(x); // => { key: "123" }
随着版本2的更新,value
已删除subscribe()
:
已删除用于从Store中同步提取最新状态值的API。相反,如果必须获取状态值,则可以始终依赖
function getState(store: Store<State>): State { let state: State; store.take(1).subscribe(s => state = s); return state; }
同步运行:
/tmp/imagenet/classify_image_graph_def.pb
答案 1 :(得分:7)
withLatestFrom()
或combineLatest()
方法可以满足您的需求,并与Observables + Ngrx的精神保持一致。
代替上面代码中的GET STATE .mergeMap()
,使用withLatestFrom()
看起来像这样:
...
.withLatestFrom(store$, (payload, state) => {
return {payload: payload, stateData: state.data}
} )
...
顺便说一下,原始问题中的代码似乎是在管理redux操作的异步效果,这正是ngrx/effects库的用途。我建议你看看。在连接了Effects之后,用于管理异步redux操作的代码更加清晰。吉姆林奇的这篇文章对我也很有帮助:The Basics of "ngrx/effects", @Effect, and Async Middleware for "ngrx/store" in Angular 2
答案 2 :(得分:6)
并非严格地直接回答问题,但我发现此页面正在寻找如何从商店中检索单个值。
为实现此目的,您可以从State
注入@ngrx/store
对象,如下所示:
import { State } from '@ngrx/store';
constructor (private state: State<AppState>) {
let propertyValue = state.getValue().path.to.state.property;
}
state
对象将当前状态保存在私有_value
属性中,由.getValue()
方法访问。
答案 3 :(得分:5)
在@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)
);
答案 4 :(得分:1)
我创建了一个简约应用程序,其状态包含2个计数器,这些计数器是AppState的属性,还有2个reducer。每个reducer都绑定到一个特定的计数器,我为每个计数器订阅了一个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 { }
答案 5 :(得分:0)
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);
}
答案 6 :(得分:0)
这对我有用。您需要从“ @ ngrx / store”导入Store,并且AppState是您的状态。
private state: AppState;
constructor(private store: Store<AppState>) { }
ngOnInit() {
this.store.select(x => this.state = x).subscribe();
}
答案 7 :(得分:0)
从v4.x开始,我们不得不像这样将take
运算符放入管道中,以使其同步:
function getState(store: Store<State>): State {
let state: State;
store.pipe(take(1)).subscribe(s => state = s);
return state;
}
答案 8 :(得分:0)
要从商店同步获取值,您必须订阅商店,但不是将订阅存储在 Observable 中,您只需将其传递给变量。您也可以使用选择器来执行此操作。
let id: string;
this.store.select(fromWhatever.selectId).subscribe(i => id = i);
答案 9 :(得分:0)
这只是我对这个问题的经验,而不是标准的 code
。
请看github中的答案: State snapshot #227
我想在 state
中获得 constractor
,所以我习惯于 unasynchronous
:
constructor (private state: State<AppState>) {
this.store.select("yourSelector").forEach(yourSelector => {
this.property = yourSelector.path.to.state.property
});
}
答案 10 :(得分:-1)
额外评论。当我使用this._store.value.StateReducer.currentPeriod.id
时Transpiler return“app / state / stateService.ts(133,35):error TS2339:'AppState'类型中不存在属性'StateReducer'。”
constructor ( public _store: Store<AppState>) {
const store$ = this._store.select ('StateReducer');
.../...
let saveTransaction = this.actions$
.filter (action => action.type==SAVE_TRANSACTION )
.map (action => { return { type:SAVING_TRANSACTION, payload : action.payload }; } )
.mergeMap ( action => this._transactionService.updateTransaction (
this._store.value.StateReducer.currentProfile.id,
this._store.value.StateReducer.currentPeriod.id,
action.payload),
(state, webServiceResponse) => { return { type:TRANSACTION_UPDATED, payload :null }; }) ;
}
要解决问题,我更改了rxjs \ subject文件夹中的BehaviorSubject.d.ts:
import { Subject } from '../Subject';
import { Subscriber } from '../Subscriber';
import { Subscription } from '../Subscription';
export declare class BehaviorSubject<T> extends Subject<T> {
private _value;
private _hasError;
private _err;
constructor(_value: T);
getValue(): T;
value: T; <=== I have changed it to value: any;
_subscribe(subscriber: Subscriber<any>): Subscription<T>;
_next(value: T): void;
_error(err: any): void;
}
不确定这是否是合法修改;)
答案 11 :(得分:-2)
这对我有用。我将获取我的对象数据。
sig