简体   繁体   English

关于基于可观察变量的归并的混淆

[英]Confusion regarding observables merging based on their return

I am working on an angular2 application which uses ngrx store approach to manage states. 我正在开发一个使用ngrx存储方法来管理状态的angular2应用程序。 App is open source on github here 应用程序是开源GitHub上这里

Problem statement 问题陈述

Specific problem I am facing with this approach is using values emitted from one observable when other observable returns null . 我用这种方法面临的特定问题是,当其他可观察值返回null时,使用从一个可观察值发出的值

I don't want to query backend api when I have data present in my ngrx store . 当我的ngrx 存储中存在数据时,我不想查询后端api


Angular2 Code Angular2代码

Below is my trips.reducer.ts file 以下是我的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;
}

Below is my base reducer index.ts 以下是我的基本减速器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];
});

Now I can get a particular trip in trip-detail.component.ts like this 现在,我可以像这样在trip-detail.component.ts进行特定的旅行

selectedTrip$: Trip;

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

Now if I reload the route localhost:4200/trips/2 , then our store will initialize to initialState that is shown below 现在,如果我重新加载路由localhost:4200/trips/2 ,那么我们的商店将初始化为initialState,如下所示

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

and below method will not work as getTrips and getSelectedTripId will be null 和下面的方法将无法正常工作,因为getTrips和getSelectedTripId将为null

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

So now I can make a backend request which will load only the single trip based on the url id like this 因此,现在我可以发出一个后端请求,该请求将仅基于url id加载单次旅行,如下所示

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

But i want to make backend request only when the trip is not present in the store and 但是我只想在商店中不存在旅行时提出后端请求

this.selectedTrip$ returns null or undefined. this.selectedTrip $返回null或未定义。

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

If you need the data to be ready before the component is being shown you could use a resolver. 如果您需要在显示组件之前准备好数据,则可以使用解析器。 See this answer here . 在这里查看此答案。

In your case it would look the following and the resolver would only make sure that the loading of the data is initialized if selectedTrip is null . 在您的情况下,它将看起来如下所示,并且如果selectedTripnull ,则解析程序将仅确保初始化数据加载。 Note: As we won't use the returned data of the resolver anywhere, we can just return anything. 注意:由于我们不会在任何地方使用解析器的返回数据,因此我们可以返回任何内容。

@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
            }
        });

} }

Here the resolver will make sure that the load actions are triggered when the selectedTrip data is not ready. 在这里,解析器将确保在selectedTrip数据未准备好时触发加载操作。

In the trip-detail.component you'll only need to wait for valid data. trip-detail.component您只需要等待有效数据即可。 Like so: 像这样:

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

Hope that makes sense and helps you. 希望这对您有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM