上下文: Angular 4.x,RxJs 5.4.x,NgRx 4.1.1。
目标:我想避免在多个组件请求相同数据时重复相同的api调用。我不想取消飞行中的请求,只是在飞行中的请求完成之前不要做好未来的请求。
方法:在商店中有一个名为isFetching
的标记。在我的效果中,我检查标志,看看是否已经有飞行中的请求。如果是,那么我不提出请求。触发效果的相同操作会将isFetching
标志设置为true。
问题:在运行效果之前更新状态。因此isFetching
在发送第一个请求之前为真。所以没有发送任何请求。
示例:以下是问题的简化版本:
state.ts
export interface State {
isFetching: boolean;
}
reducer.ts
export function reducer(state: State, action: Action): State {
switch (action.type) {
case 'FETCH':
return <State>{ isFetching: action.payload };
}
return state;
}
effect.ts
@Effect()
public fetch: Observable<Action> = this.actions.ofType('FETCH')
.withLatestFrom(this.store.select(x => x.isFetching), (_, x) => x)
.filter(x => !x)
.switchMap(action =>
this.api.getData()
.map(data => new FetchSuccess(data))
.catch(() => Observable.of(new FetchFailure()))
);
想法#1:
我可以通过在包含效果的类中保留变量来复制状态。我会在api请求发出时设置它并使用它来过滤掉将来的请求。
effect.ts
public isFetching = false;
@Effect()
public fetch: Observable<Action> = this.actions.ofType('FETCH')
.filter(() => !this.isFetching)
.switchMap(action => {
this.isFetching = true;
return this.api.getData()
.map(data => new FetchSuccess(data))
.catch(() => Observable.of(new FetchFailure()))
.do(() => this.isFetching = false);
});
想法#2:
没有'FETCH'
操作集isFetching
。让效果发出两个动作。第一个(IsFetching
)设置状态,第二个(FetchSuccess | FetchFailure
)是结果。我不喜欢我需要两个动作去做我觉得我应该能做的事情。优点是,如果有多个'FETCH'
请求,则IsFetching
操作只会有一个状态更新。
似乎效果的结果异步应用于状态。因此,顺序同步'FETCH'
操作将在标志设置为状态之前触发相同数量的请求。所以不要使用这个解决方案。
effect.ts
@Effect()
public fetch: Observable<Action> = this.actions.ofType('FETCH')
.withLatestFrom(this.store.select(x => x.isFetching), (_, x) => x)
.filter(x => !x)
.switchMap(action =>
this.api.getData()
.map(data => new FetchSuccess(data))
.catch(() => Observable.of(new FetchFailure()))
.startWith(new IsFetching(true))
);
问题 是否有更优雅/标准的方式来实现我的目标?理想情况下,我希望避免在两个地方保留相同的状态信息。
答案 0 :(得分:7)
一种选择是使用维持自己状态的运算符。
例如,你可以使用distinct
,它接受第二个参数,在发射时清除操作员的内部状态:
@Effect()
public fetch: Observable<Action> = this.actions
.ofType('FETCH')
.distinct(() => 'FETCH', this.actions.ofType(
'FETCH_SUCCESS',
'FETCH_FAILURE'
))
.switchMap(action => this.api.getData()
.map(data => new FetchSuccess(data))
.catch(() => Observable.of(new FetchFailure()));
);
如果键选择器始终返回相同的值,则在处理一个时收到的任何FETCH
操作都将被忽略。