Как получить текущее значение объекта 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
Ответы
Ответ 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;
}
Не уверен, что это законная модификация;)