Подтвердить что ты не робот

Как получить текущее значение объекта State с помощью @ngrx/store?

Мой класс сервиса перед вызовом веб-службы должен получить свойство (в моем примере: 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));

}

PS: Я использую 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

4b9b3361

Ответ 1

Оригинальный ответ для @ngrx/store v1.x

@ngrx/store extends 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:

API-интерфейсы для синхронного вытягивания последнего значения состояния из хранилища были удалены. Вместо этого вы всегда можете полагаться на subscribe(), работая синхронно, если вам нужно получить значение состояния:

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

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

    return state;
}

Ответ 2

withLatestFrom() или combineLatest() в цепочке подписки дают вам именно то, что вам нужно, и выровнены с духом Observables + Ngrx.

Вместо GET STATE .mergeMap() в приведенном выше коде использование withLatestFrom() будет выглядеть примерно так:

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

Как и в стороне, код в исходном вопросе, по-видимому, управляет асинхронными эффектами действий redux, что как раз то, что ngrx/effects библиотека для. Я предлагаю вам проверить это. После того, как вы активируете Effects, код для управления асинхронными действиями redux намного чище. Эта статья Джима Линча также была очень полезна для меня: Основы "ngrx/effects" , @Effect и промежуточного ПО Async для "ngrx/store" в Angular 2

Ответ 3

Не совсем прямой ответ на вопрос, но я нашел эту страницу для поиска того, как получить одно значение из хранилища.

Чтобы добиться этого, вы можете ввести объект State из @ngrx/store, как показано ниже:

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

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

Объект State содержит текущее состояние в закрытом свойстве _value, к которому обращается метод .getValue().

Ответ 4

Дополнительный комментарий. Когда я использую this._store.value.StateReducer.currentPeriod.id

Transpiler return "app/state/stateService.ts(133,35): ошибка TS2339: свойство 'StateReducer' не существует в типе 'AppState'."

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





}

Чтобы устранить проблему, я изменил BehaviorSubject.d.ts в папке rxjs\subject:

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

Не уверен, что это законная модификация;)