如何使用@ngrx/store获取State对象的当前值?

Phi*_*lon 40 rxjs5 ngrx angular

在调用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));

}
Run Code Online (Sandbox Code Playgroud)

我正在使用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

Sas*_*sxa 55

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

@ngrx/store扩展BehaviorSubject并且它具有value您可以使用的属性.

this._store.value
Run Code Online (Sandbox Code Playgroud)

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

更新:

花了一些时间来计算你的例子中的内容(:要获得当前值dataForUpdate,你可以使用:

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

@ ngrx/store v2.x的更新

随着版本2的更新,value已按文档中的描述删除:

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

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

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

    return state;
}
Run Code Online (Sandbox Code Playgroud)

  • “您始终可以依靠同步运行的subscription()”可以吗?订阅是否同步?对我来说,在您的示例中,执行订阅回调之前,“状态”可能会以未定义状态返回。 (8认同)
  • `take(1)` 不会使其同步,它只是使其发出一次,但仍然是异步发生的。 (5认同)
  • @JeffryHouser,rjxs 强制您现在使用管道,`store.pipe(take(1)).subscribe()` (4认同)
  • @Forge_7 `take()` 运算符使其同步 http://reactivex.io/rxjs/file/es6/operator/take.js.html#lineNumber73 (用于存储可观察值),对于其他可观察值,你可能是对的,理论上它可以是同步的也可以是异步的... (3认同)
  • @Sasxa是的,调用链可以是这样的,但是 (s =&gt; state = s) 正在传递一个函数,并且不知道它是同步回调还是异步回调,而不知道回调时会发生什么(内订阅)。所以我的新问题是这样的:Observable中的subscribe方法回调函数是同步还是异步?它取决于 Observable 的类型吗?例如,Angular 的 http 库提供给我们的 Observable 绝对是异步的。 (2认同)
  • 这个答案似乎不再起作用.我正在获取一个属性`在类型商店中不存在. (2认同)
  • 这里是否存在订阅完成之前返回的风险? (2认同)

小智 11

根据@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;
}
Run Code Online (Sandbox Code Playgroud)

或者,严格使用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;
}
Run Code Online (Sandbox Code Playgroud)

而且,如果您想使代码更具可读性,还可以采用如下的异步/等待机制:

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;
}
Run Code Online (Sandbox Code Playgroud)

  • Pipe并没有使更改更容易,它使难度和冗长变得更加困难。引入管道并不是为了使链接更容易,而是简化了树状交换。首先,我认为塑造api来满足工具的要求是​​错误的,但要牺牲程序员的精力,但是会浪费很多。 (5认同)
  • 不,将开发人员体验置于用户体验之上是错误的。巨大的、未摇动的捆绑包并不是一件好事。 (3认同)

Ale*_*ark 8

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

为此,您可以State@ngrx/store下面注入对象:

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

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

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

  • 应该注意的是,在编写本文时(@ngrx v4.1.1),注入"State"会导致与Redux DevTools一起使用时出现问题,**重复调度的每个操作**.尽管比较简洁,但也许不是最实用的路线. (3认同)

Mat*_*iba 7

withLatestFrom()或者combineLatest()订阅链中的方法可以满足您的需求,并与Observables + Ngrx的精神保持一致.

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

...
.withLatestFrom(store$, (payload, state) => { 
    return {payload: payload, stateData: state.data} 
} )
...
Run Code Online (Sandbox Code Playgroud)

顺便说一句,原始问题中的代码似乎是在管理redux动作的异步效果,这正是ngrx/effects库的用途.我建议你看看.在连接了Effects之后,用于管理异步redux操作的代码更加清晰.Jim Lynch撰写的这篇文章对我也非常有帮助:Angular 2中"ngrx/store"的基础知识,@ Effect和Async中间件"ngrx/store"


小智 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);
}
Run Code Online (Sandbox Code Playgroud)


Lin*_* Vu 5

@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;
}

Run Code Online (Sandbox Code Playgroud)