Нет данных о первой загрузке - PullRequest
0 голосов
/ 26 апреля 2019

Я новичок в NgRx и пытаюсь извлечь и кэшировать данные таблицы с разбивкой по страницам, используя Effects и запрос http. Но при любой первой загрузке страницы (если страница еще не кэширована) я получаю пустую страницу, даже если я делаю console.log объекта состояния, я вижу данные внутри? Когда я перехожу на предыдущую страницу, там есть данные, поэтому я предполагаю, что в асинхронном мире я что-то не так делаю, но не могу понять, что: /

вот моя инициализация в component.ts

  ngAfterViewInit() {

    this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);

    merge(this.sort.sortChange, this.paginator.page)
      .pipe(
        startWith({}),
        switchMap(() => {
          this.isLoadingResults = true;

          this.store.dispatch(new ListLoad(this.getQueryParams()));

          return this.store.pipe(select('list'));
         }),
        map((state: State) => {
          this.isLoadingResults = false;
          this.resultsLength = state.totalRecords;

          return this.cacheKey in state.data ? state.data[this.cacheKey] : [];
        }),
        catchError((err) => {
          this.isLoadingResults = false;
          this.resultsLength = 0;

          return observableOf([]);
        })
      )
      .subscribe((data: any[]) => {
        return this.data = data
      });
  }

и вот мое определение эффекта effects.ts

@Effect()
loadData = this.actions$.pipe(
    ofType(actions.actionTypes.ListLoad),
    mergeMap((action: actions.actionTypes.ListLoadSuccess) => this.service.getAll(action.payload).pipe(
        map(
            response => {
                let apiResponse = new ApiResponse(response);
                let cacheKey = JSON.stringify(action.payload);

                return apiResponse.isSuccess ?
                    new actions.ListLoadSuccess({ key: cacheKey, data: apiResponse.data }) :
                    new actions.ListLoadFailed(`code: ${apiResponse.status.error_code}; message: ${apiResponse.status.error_message}`);
            }
        ),
        catchError(err => observableOf(new actions.ListLoadFailed(err)))
    ))
)

В дополнение к этому я хотел бы отменить http-запрос, если в хранилище NgRx присутствует страница, содержащая данные

1 Ответ

0 голосов
/ 28 апреля 2019

Я смог решить это. Проблема заключалась в том, что я обновлял свойство store, являющегося объектом, добавляя в него новое свойство. Хранилище не отправляет событие об обновлении фрагмента, поэтому выбор подписки не срабатывает. Я ввел еще один логический параметр для состояния загрузки, который прослушивает изменения, и если загрузка ложна (страница загружена), я выбираю нужный фрагмент. Я также добавил дополнительный код для кэширования страниц

component.ts

  ngOnInit() {

    this.isLoadingResults$ = this.store.pipe(
      select(state => state.stateFragment.isListLoading),
      takeWhile(() => this.componentActive) //unsubscribe
    );

    this.store.dispatch(new ListLoad());

    this.isLoadingResults$.pipe(
      filter((isLoading:boolean) => !isLoading),
      switchMap(() => this.store.pipe(
        select(state => state.stateFragment),
        takeWhile(() => this.componentActive) //unsubscribe
      )),
      map(...)
    ).subscribe(...);

    //Other stuff here

  }

effects.ts

@Effect()
    load$ = this.actions$.pipe(
        ofType(actions.actionTypes.ListLoad),
        withLatestFrom(this.store.pipe(select(state.stateFragment))),
        filter(([action, store]) => {
            let isPageCached: boolean = action.payload in store.stateFragment;
            if (isPageCached) {
                this.store.dispatch(new actions.ListLoaded()); //for sake of changing loading state
            }
            return !isPageCached;
        }),
        switchMap(([action, store]) => {
            return this.service.getAll(action.payload).pipe(
                map(
                    response => {
                        let apiResponse = new ApiResponse(response);
                        return apiResponse.isSuccess ?
                            new actions.ListLoadSuccess({ key: action.payload, data: apiResponse.getData(), totalRecords: apiResponse.getTotalCount() }) :
                            new actions.ListLoadFailed(`code: ${apiResponse.status.error_code}; message: ${apiResponse.status.error_message}`);
                    }
                ),
                catchError(err => observableOf(new actions.ListLoadFailed(err)))
            );
        }
        ), share()
    )

reducer.ts

export function reducer(state = initialState, action: Actions) {
    switch (action.type) {
        case actionTypes.ListLoad:
            return {
                ...state,
                isListLoading: true
            };
        case actionTypes.ListLoaded:
            return {
                ...state,
                isListLoading: false
            };
        case actionTypes.ListLoadSuccess:
            state.listData[action.payload.key] = action.payload.data;

            return {
                ...state,
                isListLoading: false,
                listData: state.listData,
                listTotal: action.payload.totalRecords
            };
        case actionTypes.ListLoadFailed:
            return {
                ...state,
                isListLoading: false,
                error: action.payload
            };
        case actionTypes.ListClear:
            return {
                ...state,
                listData: {},
                listTotal: 0
            };;
        default:
            return state;
    }
}
...