typescript - چگونه یک افکت را در انتظار یک Observable با استفاده از @ngrx/effects قرار دهیم


من در برنامه Angular 2 خود از @ngrx/effects استفاده میکنم و در تلاش برای پیادهسازی تأثیری که وابسته به شرایطی بر اساس وضعیت برنامه است، با برخی مشکلات مواجه شدهام.

در حالت من، من یک نقشه از موقعیت -> تواناییها دارم، که بر اساس locationId کلیدگذاری شده است (و همچنین نقشههای دیگری از موقعیت -> *). وقتی ACTION_A رخ میدهد، من فقط میخواهم که وقتی تواناییها برای موقعیت فعلی بهروز هستند ادامه یابد. وقتی ACTION_A ارسال میشود، ممکن است تواناییها قبلاً بهروز باشند، اما برنامه همچنین میتواند در حال بارگذاری تواناییهای جدید باشد.

با کد زیر، وقتی ACTION_A یک بار ارسال شود، isOutOfDate هر بار که هر عملی به فروشگاه ارسال میشود فراخوانی میشود. بنابراین، به نظر میرسد که قابل مشاهده هنوز فعال است، حتی پس از آنکه فیلتر بهروز شده برآورده شده است. با این حال، اگر getCapabilities با getCapabilitiesWorking جایگزین شود، آنگاه isOutOfDate فقط تا زمانی که شرط فیلتر هر بار که عمل ACTION_A ارسال میشود برآورده شود فراخوانی میشود، همانطور که انتظار میرود از هر کدام از پیادهسازیها.

به نظر میرسد من در مورد نحوه کار combineLatest یا filter یا take چیزی را از دست دادهام...

یا شاید من دارم کل این کار را اشتباه انجام میدهم ...

من ترجیح میدهم بتوانم از تابع رایج برای انتخابکنندههای «موقعیت فعلی» خود استفاده کنم

ایدهای داری؟

@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 مدام فراخوانی میشود، با این حال "برخی کارها را انجام بده" انجام نمیشود...

پاسخ شماره ۱

شما ممکن است تلاش کنید فیلتر در switchMap را با skipWhile جایگزین کنید

پس اثر خواهد بود:

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

این به من در یک مورد استفاده مشابه کمک کرد :)

پاسخ شماره ۲

withLatestFrom کار نخواهد کرد، زیرا observable حاصل تنها زمانی خروجی میدهد که منبع منشأ (action dispatched) ارسال شود، طبق مستندات شما نیاز به combineLatest دارید، بنابراین:

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