如何使用@ ngrx / effects对Observable进行效果等待

时间:2016-12-05 20:32:20

标签: rxjs ngrx

我在Angular 2应用程序中使用@ ngrx / effects,我在尝试实现依赖于基于应用程序状态的条件的效果时遇到了一些问题。

在我的州,我有一张位置地图 - >功能,由locationId键入(以及其他位置地图 - > *)。当ACTION_A发生时,我只希望一旦有当前位置的最新功能就继续。调度ACTION_A时,可能的功能已经是最新的,但是,应用程序也可能正在加载新的功能。

使用下面的代码,一旦调度ACTION_A,每次任何操作被调度到商店时,都会调用isOutOfDate。因此,即使在满足最新的过滤器之后,似乎仍然可以观察到observable。但是,如果将getCapabilities替换为getCapabilitiesWorking,则只有在每次调度isOutOfDate操作时满足过滤条件时才会调用ACTION_A,正如我所期望的那样实施

所以,似乎我遗漏了combineLatestfiltertake的工作方式......

或许我正在接近这一切......

我宁愿能够将常用功能用于我的“当前位置”选择器

有什么想法吗?

@Effect() route$ = actions$
    .ofType(ACTION_A)
    .switchMap(() => this._store.let(getCapabilities)
        .filter(capabilities => !isOutOfDate(capabilities))
        .take(1)
    )
    .map( do some stuff );

// Selector function that causes excess observable emits
export const getCapabilities =
     compose(fromLocations.currentLocationLookup(fromLocations.getCapabilities), fromRoot.getLocations);

// Selector function works as expected
export const getCapabilitiesWorking = function (state$: Observable<AppState>): Observable<Capability> {
    return state$
        .let(fromRoot.getLocations)
        .map(l => l.capabilitiesByLocation[l.currentId]);
};

// fromLocations
// -------------

export function getCapabilities(state$: Observable<LocationsState>): Observable<{ [id: string]: Capability }> {
    return state$.map(s => s.capabilitiesByLocation);
}

// Find the value in 'collection' corresponding to the current location
export function currentLocationLookup<T>(
    collection: (state$: Observable<LocationsState>) => Observable<{ [id: string]: T }>
): (state$: Observable<LocationsState>) => Observable<T> {
    return (state$: Observable<LocationsState>): Observable<T> => {
        return Observable.combineLatest(
            state$.let(getCurrentLocation),
            state$.let(collection),
            (locId, map) => map[locId]
        );
    };
}

编辑:澄清一下,isOutOfDate函数一直被调用,但是“做一些东西”不会...

3 个答案:

答案 0 :(得分:2)

@Effect() route$ = actions$ .ofType(ACTION_A) .combineLatest(this._store.let(getCapabilities)) .filter(([action, capabilities]) =>!isOutOfDate(capabilities)) .map( do some stuff ); 将不起作用,因为根据您需要的文档combineLatest,结果observable将仅在源发出(已分派的动作)时发出输出,因此:

  var mainContentHeight = $("#mainContent").height();
  var mainContentTop = $("#mainContent").offset().top;
  var sidebarHeight = $("#sidebar").height();
  var sidebar = $("#sidebar");

  $(document).on("scroll", function() {
    //'stick' sidebar to the bottom of main block if we scroll 'too far'
    if ($(window).scrollTop() + sidebarHeight > mainContentHeight + mainContentTop) {
      sidebar.css({
        position: 'absolute',
        top: mainContentHeight - sidebarHeight + mainContentTop
      });
    }
    //'stick' sidebar to the top of main block 
    else if ($(window).scrollTop() < mainContentTop) {
      sidebar.css({
        position: 'absolute',
        top: mainContentTop
      });
    }
    //fixed sidebar until it won't reach top or bottom of the main content block
    else {
      sidebar.css({
        position: 'fixed',
        top: 0
      });
    }
  });

答案 1 :(得分:2)

您可能会尝试使用skipWhile

替换switchMap中的过滤器

因此效果将是:

@Effect() route$ = actions$
.ofType(ACTION_A)
.switchMap(() => this._store.let(getCapabilities)
    .skipWhile(capabilities => !isOutOfDate(capabilities))
    .take(1)
)
.map( do some stuff );

这在一个类似的用例中帮助了我:)

答案 2 :(得分:1)

尝试使用withLatestFrom方法。你的效果可能看起来像

@Effect() route$ = actions$
.ofType(ACTION_A)
.withLatestFrom(this._store.let(getCapabilities))
.filter(([action, capabilities]) =>!isOutOfDate(capabilities)) 
.map( do some stuff );