ngrx一次在飞行中请求一个

byg*_*ace 4 rxjs ngrx angular

上下文: Angular 4.x,RxJs 5.4.x,NgRx 4.1.1.

目标:当多个组件请求相同的数据时,我希望避免重复相同的api调用.我不想取消飞行中的请求,只是在飞行中的请求完成之前不要取得未来的请求.

方法:在商店中有一个名为的标志isFetching.在我的效果中,我检查标志,看看是否已经有飞行中的请求.如果是,那么我不提出请求.触发效果的相同操作会将isFetching标志设置为true.

问题:在运行效果之前更新状态.因此,isFetching发送的第一个请求之前,是真实的.所以没有发送任何请求.

示例:以下是问题的简化版本:

state.ts

export interface State {
    isFetching: boolean;
}
Run Code Online (Sandbox Code Playgroud)

reducer.ts

export function reducer(state: State, action: Action): State {
    switch (action.type) {
        case 'FETCH':
            return <State>{ isFetching: action.payload };
    }

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

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

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

想法#2:

没有'FETCH'设置动作isFetching.让效果发出两个动作.first(IsFetching)设置状态,second(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))
    );
Run Code Online (Sandbox Code Playgroud)

问题 有没有更优雅/标准的方法来实现我的目标?理想情况下,我希望避免在两个地方保留相同的状态信息.

car*_*ant 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()));
    );
Run Code Online (Sandbox Code Playgroud)

如果键选择器始终返回相同的值,FETCH则将忽略在处理一个键时选择的任何操作.