【问题标题】:Confusion regarding observables merging based on their return关于基于返回值合并的 observables 的困惑
【发布时间】:2016-12-06 12:34:21
【问题描述】:

我正在开发一个使用 ngrx 存储方法来管理状态的 angular2 应用程序。应用在github上开源here

问题陈述

我在使用这种方法时面临的具体问题是,当其他可观察对象返回 null 时,使用从一个可观察对象发出的值

当我的ngrx 存储中有数据时,我不想查询后端api。


Angular2 代码

下面是我的trips.reducer.ts文件

export interface State {
  ids: string[];
  trips: { [id: string]: Trip };
  selectedTripId: string;
}

const initialState = {
  ids: [],
  trips: {},
  selectedTripId: null
}

export function reducer(state = initialState, action: Action ): State {}

export function getTrips(state : State) {
  return state.trips;
} 

export function getTripIds(state: State) {
  return state.ids;
}

export function getSelectedTripId(state: State) {
  return state.selectedTripId;
}

下面是我的基本减速器index.ts

export interface State {
  trips: fromTripsReducer.State;    
} 

const reducers = {
  trips: fromTripsReducer.reducer,
}

export function getTripsState(state: State): fromTripsReducer.State {
  return state.trips;
}

export const getTrips = createSelector(getTripsState, fromTripsReducer.getTrips);
export const getTripIds = createSelector(getTripsState, fromTripsReducer.getTripIds);
export const getSelectedTripId = createSelector(getTripsState, fromTripsReducer.getSelectedTripId);
export const getSelectedCityId = createSelector(getTripsState, fromTripsReducer.getSelectedCityId);

export const getTripsCollection = createSelector(getTrips, getTripIds, (trips, ids) => {
  return ids.map(id => trips[id]);
});

export const getSelectedTrip = createSelector(getTrips, getSelectedTripId, (trips, id) => {
  return trips[id];
});

现在我可以像这样在trip-detail.component.ts 获得特定的旅行

selectedTrip$: Trip;

constructor(private store: Store<fromRoot.State>) {
  this.selectedTrip$ = this.store.select(fromRoot.getSelectedTrip);
}

现在如果我重新加载路由localhost:4200/trips/2,那么我们的商店将初始化为如下所示的initialState

const initialState = {
  ids: [],
  trips: {},
  selectedTripId: null
}

以下方法将不起作用,因为 getTrips 和 getSelectedTripId 将为空

export const getSelectedTrip = createSelector(getTrips, getSelectedTripId, (trips, id) => {
  return trips[id];
});

所以现在我可以发出一个后端请求,该请求将只加载基于 url id 的单程,像这样

return this.http.get(`${this.apiLink}/trips/${trip_id}.json`
  .map((data) => data.json())

但我只想在商店中不存在旅行时发出后端请求并且

this.selectedTrip$ 返回 null 或 undefined。

this.selectedTrip$ = this.store.select(fromRoot.getSelectedTrip);

【问题讨论】:

    标签: angular typescript redux observable ngrx


    【解决方案1】:

    如果您需要在显示组件之前准备好数据,您可以使用解析器。看到这个答案here

    在您的情况下,它将如下所示,并且解析器只会确保在 selectedTripnull 时初始化数据的加载。注意:由于我们不会在任何地方使用解析器返回的数据,所以我们可以返回任何东西。

    @Injectable()
    export class SelectedTripResolver implements Resolve {
    
    constructor(
        private store: Store
    ) {}
    
    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
    
        // get the selectedTrip
        return this.store.select(fromRoot.getSelectedTrip)
            // check if data is ready. If not trigger loading actions
            .map( (selectedTrip) => {
                if (selectedTrip === null) {
                    //trigger action for loading trips & selectedTrip
                    this.store.dispatch(new LoadTripAction());
                    this.store.dispatch(new LoadselectedTripAction());
                    return false; // just return anything
                } else {
                    return true; // just return anything
                }
            });
    

    }

    在这里,解析器将确保在selectedTrip 数据未准备好时触发加载操作。

    trip-detail.component 中,您只需要等待有效数据。像这样:

    constructor(private store: Store<fromRoot.State>) {
        this.selectedTrip$ = this.store.select(fromRoot.getSelectedTrip)
            .filter(selectedTrip => selectedTrip !== null);
    }
    

    希望这有意义并能帮助你。

    【讨论】:

      猜你喜欢
      • 2013-04-08
      • 2016-04-02
      • 2022-01-05
      • 1970-01-01
      • 1970-01-01
      • 2019-10-26
      • 2018-04-10
      • 1970-01-01
      • 2019-05-12
      相关资源
      最近更新 更多