Сервер вызовов NGRX только в конце - PullRequest
0 голосов
/ 05 июля 2018

В моем приложении Angular у меня есть эффект (обрабатывается при запуске приложения), который получает доступные ланги с сервера. Я собираюсь сохранить lang [] внутри объекта ( GlobalData ), сохраненного в магазине приложений. В компоненте входа в систему я подписываюсь на свойство isFetchingLangs , логическое значение, которое, если оно истинно, отключит вход в систему. Итак, шаги эффектов следующие:

  1. Получить GlobalData из магазина
  2. Если есть langs, установите для isFetchingLangs значение false и сохраните факт создания GlobalData; в противном случае позвоните в сервис;
  3. Подготовка действий к отправке: если GlobalData отсутствует, я добавляю langs и добавляю действие для сохранения GlobalData. установите для isFetchingLangs значение false

Это код:

coreActions$ = this.actions$
    .ofType(CoreActions.GET_AVAILABLE_LANGS)
    .pipe(
        withLatestFrom(this.store.select(fromApp.getGlobalData))
        , take(1) 
        , map(([action, storeState]) => {
            if (storeState && storeState.langs && storeState.langs.length) {
                this.globaDataCreated = true;
                return this.store.dispatch(new CoreActions.GetAvailableLangsFinished());
            } else {
                return from(this.langsService.getAvailableLangs());
            }
        })
        , mergeMap((langs: Lang[]) => {
            let actions = [];
            if (!this.globaDataCreated) {
                this.applicationUrl = this.urlService.getApplicationUrl();
                let newGlobalData = new GlobalData(
                    false,
                    null
                );

                langs.forEach(lang => {
                    newGlobalData.langs.push(lang)
                });
                this.translate.use('en');
                this.moment.tz.setDefault("UTC");
                actions.push({
                    type: CoreActions.SET_CORE_APPLICATION_DATA, 
                    payload: newGlobalData
                })
            }

            actions.push({
                type: CoreActions.GET_AVAILABLE_LANGS_FINISHED
            })

            return actions;
        })
        , catchError((err, caught) => { ...... }

Услуга:

getAvailableLangs(): any {
    return this.http.get<CommonClasses.SenecaResponse<CommonClasses.Lang[]>>(this.applicationData.applicationContext + 'rest-api/langs');
}

Проблема: он входит в mergeMap ((langs: Lang []) => {....} перед вызовом службы this.langsService.getAvailableLangs ()

Цель: подождать, пока getAvailableLangs () не завершится, а затем установить isFetchingLangs в false и выполнить другие операции

****** РЕДАКТИРОВАННЫЙ КОД ПОСЛЕ ОТЧЕТА @JANRECKER *********

getAvaibleLang(storeState?: GlobalData) {
    if (storeState && storeState.langs && storeState.langs.length) {
        return this.store.dispatch(new CoreActions.GetAvailableLangsFinished());
    } else {
        return this.langsService.getAvailableLangs();
    }
}

@Effect()
coreActions$ = this.actions$
    .ofType(CoreActions.GET_AVAILABLE_LANGS)
    .pipe(
        withLatestFrom(this.store.select(fromApp.getGlobalData))
        , take(1) 
        , switchMap(([action, storeState]): Lang[] => this.getAvaibleLang(storeState))
        , mergeMap(
            (langs: Lang[]) => {
                if (langs) {
                    const applicationUrl = this.urlService.getApplicationUrl();
                    let newGlobalData = new GlobalData(
                        applicationUrl,
                        false,
                        null
                    );
                    langs.forEach(lang => {
                        newGlobalData.langs.push(lang)
                    });
                    this.translate.use('en');
                    return [{
                        type: CoreActions.SET_CORE_APPLICATION_DATA,
                        payload: newGlobalData
                    }, {
                        type: CoreActions.GET_AVAILABLE_LANGS_FINISHED
                    }];
                } else {
                    return [{
                        type: CoreActions.GET_AVAILABLE_LANGS_FINISHED
                    }];
                }
            }
        )
        , catchError((err, caught) => {....}

1 Ответ

0 голосов
/ 05 июля 2018

Имейте в виду, что «карта» изменяет содержимое потока.

of('helloWorld').pipe(
    map((data:string):number => data.length) // data.length = 10
).subscribe(
    (data:number) => console.log(data) )  // 10
)

Вы написали что-то вроде (я использую набор текста, чтобы сделать его немного более очевидным)

of('helloWorld').pipe(
    map((data:string):Observable<number> => from(data.length))
).subscribe(
    (data:Observable<number>) => ... )
)

Итак, вы создали наблюдаемое в наблюдаемом потоке. : -)

Если вы хотите открыть второй поток, правильным выбором будет «mergeMap». Если первый поток сделал все, что вы хотите, и вы хотите работать сейчас в другом потоке, то SwitchMap был бы моим выбором.

Просто чтобы лучше понять код, я бы извлек все из потока в методы. Что-то вроде

coreActions$ = this.actions$
    .ofType(CoreActions.GET_AVAILABLE_LANGS)
    .pipe(
        withLatestFrom(this.store.select(fromApp.getGlobalData))
        , take(1)
        ,switchMap(([action,storeState]):Lang[] => this.getAvaibleLang(storeState) )
        ,tap(() => this.setApplicationUrl() )
        ,tap((langs:Lang[])=> this.setLanguages(langs) )
        ,tap(()=> this.pushLanguageAction() )
   )

С интенсивным использованием наборов, я думаю, это становится более читабельным.

С уважением

...