72

我的服务类,在调用 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 ) 作为指导。

我想知道是否存在更好(更清洁)的方式?

现场示例:https ://plnkr.co/edit/WRPfMzPolQsYNGzBUS1g?p=preview

4

11 回答 11

81

@ngrx/store v1.x 的原始答案

@ngrx/store扩展了BehaviorSubject并且它有一个value你可以使用的属性。

this._store.value

这将是您应用程序的当前状态,您可以从那里选择属性、过滤器、地图等...

更新:

花了我一段时间来弄清楚您的示例中的内容(:要获取 的当前值dataForUpdate,您可以使用:

let x = this._store.value.StateReducer.dataForUpdate;
console.log(x); // => { key: "123" }

@ngrx/store v2.x 的更新

随着对版本 2 的更新,value已删除,如docs中所述:

用于从 Store 中同步拉取最新状态值的 API 已被移除。subscribe()相反,如果您必须获取状态值,您始终可以依赖同步运行:

function getState(store: Store<State>): State {
    let state: State;

    store.take(1).subscribe(s => state = s);

    return state;
}
于 2016-02-25T18:17:51.690 回答
24

根据@Sasxa 的回答,新版本@nrgx/store(v5 和 v6)的语法发生了变化。在底层 RxJS 库更新到 ^5.5.0 后,现在所有Observable实例上都有一个可用的管道方法,它允许更轻松地链接并更改订阅的实现方式。

因此,您现在可以执行以下操作:

import { take } from 'rxjs/operators';

function getState(store: Store<State>): State {
   let state: State;

   store.select('your-state').pipe(take(1)).subscribe(
      s => state = s
   );

   return state;
}

或者,严格使用pipe()运算符:

import { select } from '@ngrx/store';
import { take } from 'rxjs/operators';

function getState(store: Store<State>): State {
   let state: State;

   store.pipe(select('your-state'), take(1)).subscribe(
      s => state = s
   );

   return state;
}

如果你想让你的代码更具可读性,你还可以使用 async/await 机制,如下所示:

import { select } from '@ngrx/store';
import { take } from 'rxjs/operators';

function async getStateAsync(store: Store<State>): State {
   let state = await store
             .pipe(
                select('your-state'),
                take(1)
             )
             .toPromise<State>();

   return state;
}
于 2018-09-29T17:30:36.533 回答
14

严格来说不是对这个问题的直接回答,但我发现这个页面正在寻找如何从商店中检索单个值。

为此,您可以从如下所示注入State对象:@ngrx/store

import { State } from '@ngrx/store';

constructor (private state: State<AppState>) {
    let propertyValue = state.getValue().path.to.state.property;
}

state对象将当前状态保存在由方法_value访问的私有属性中。.getValue()

于 2017-12-03T12:36:56.003 回答
13

withLatestFrom()订阅链中的或combineLatest()方法可以满足您的需求,并且符合 Observables+Ngrx 的精神。

代替.mergeMap()上面代码中的 GET STATE , usingwithLatestFrom()看起来像这样:

...
.withLatestFrom(store$, (payload, state) => { 
    return {payload: payload, stateData: state.data} 
} )
...

顺便说一句,原始问题中的代码似乎是管理 redux 操作的异步效果,这正是ngrx/effects库的用途。我建议你检查一下。连接 Effects 后,管理异步 redux 操作的代码就干净多了。Jim Lynch 的这篇文章对我也很有帮助:Angular 2 中“ngrx/效果”、@Effect 和异步中间件的基础知识

于 2017-03-27T22:46:52.423 回答
7

我的解决方案


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);
}
于 2018-06-08T02:20:23.627 回答
2

@ngrx/store v4.x 的更新

从 v4.x 开始,我们被迫take像这样将运算符放入管道中以使其同步:

function getState(store: Store<State>): State {
    let state: State;

    store.pipe(take(1)).subscribe(s => state = s);

    return state;
}

于 2020-05-11T08:09:38.797 回答
1

我创建了一个简约的应用程序,它的状态具有 2 个作为 AppState 属性的计数器和 2 个减速器。每个 reducer 都绑定到一个特定的计数器,我为每个计数器订阅了一个 observable,console.log它的值。在调用时,reducers 本身也会写入控制台。

有一个按钮通过调度一个事件来调用两个减速器。此外,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 { }
于 2018-02-14T10:01:54.173 回答
0

额外评论。当我使用 this._store.value.StateReducer.currentPeriod.id

转译器返回“app/state/stateService.ts(133,35):错误 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;
}

不确定这是否是合法修改;)

于 2016-02-25T18:58:25.173 回答
0

这只是我对这个问题的经验,而不是标准code

请在 github 中查看答案: State snapshot #227

我想进去stateconstractor所以我习惯unasynchronous

constructor (private state: State<AppState>) {

   this.store.select("yourSelector").forEach(yourSelector => { 
       this.property = yourSelector.path.to.state.property 
   });

}
于 2021-02-19T06:46:58.930 回答
0

这对我有用。您需要从 '@ngrx/store' 导入商店,并且 AppState 是您的状态。

private state: AppState;

constructor(private store: Store<AppState>) { }

ngOnInit() {
    this.store.select(x => this.state = x).subscribe();
}
于 2019-11-13T11:26:43.723 回答
-2

这对我来说是工作。我会得到我的对象数据。

this.store.select('dataStore').subscribe(data => { 
          console.log(data)
 }
于 2018-08-09T06:26:05.537 回答