我有这个减速器:
heroStore.reducer.ts
import { Action } from '@ngrx/store';
import {Hero} from '../models/hero';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
export const UPDATE = '[hero] UPDATE';
export function heroReducer(state: { [heroId: string]: BehaviorSubject<Hero>; } = {}, action: Action):
{ [heroId: string]: BehaviorSubject<Hero>; } {
switch (action.type) {
case UPDATE:
let newState;
const hero: Hero = action.payload;
if (state[hero.uid]) { // hero exists
newState = state[hero.uid].next(hero);
} else {
const heroObservable = new BehaviorSubject<Hero>(hero);
newState = Object.assign({}, state, {[hero.uid]: heroObservable});
}
console.log('New State', newState);
return newState;
default:
return state;
}
}
以及以下服务
hero.service.ts
getHero(heroId: string): BehaviorSubject<Hero> {
let state;
this.store.select('heroStore').subscribe(s => state = s);
console.log('state returned in service', state);
return state[heroId];
}
最后进行以下测试:
it('should be able to get a hero', inject([HeroService], (service: HeroService) => {
expect(service).toBeTruthy();
heroReducer({}, {
type: '[hero] UPDATE',
payload: {
uid: '5',
name: 'Franz'
}
});
const heroObs = service.getHero('5');
expect(heroObs.getValue().name).toEqual('Franz');
}));
但不知何故,州没有得到更新。它产生以下日志:
日志:&#39;新状态&#39;,对象{5:BehaviorSubject {_isScalar:false, 观察者:[],关闭:false,isStopped:false,hasError:false, thrownError:null,_value:Object {uid:...,name:...}}}
日志:&#39;状态在服务&#39;,对象{}
中返回
因此reducer实际上返回了正确的新状态。但是当在服务中订阅时,我仍然得到一个空对象。
如果我理解正确,ngrx / store中的商店是一个rxjs BehaviorSubject,它反过来应该在订阅时返回 last 值。来自BehaviorSubject的文档:
观察者可以订阅主题以接收最后(或初始)值以及所有后续通知
那么状态仍然是一个空对象怎么可能呢?
答案 0 :(得分:-1)
您的getHero
编码不正确,我认为它会返回未分配的值。写一个更好的方法是:
getHero(heroId: string): BehaviorSubject<Hero> {
let state = new BehaviorSubject<Hero>();
this.store.select('heroStore').subscribe(s => state.next(s[heroId]));
return state;
}
甚至更好:
getHero(heroId: string): Observable<Heor> {
return this.store.select('heroStore')
.map(heros => heros[heroId];
}
或者如果你想真正优雅,这可能会有效:
getHero(heroId: string): Observable<Heor> {
return this.store.select('heroStore', heroId);
}