Firestore + NgRx + 实体

Firestore + NgRx + Entities

我正在努力使用 Ngrx + Firestore。我正在为我的应用程序使用 tutorial code,并且一切正常。 当我想向我的 CRUD 操作添加另一个 "query" 操作时,问题就来了。我已经设置好一切(新动作和新效果)但我不知道如何处理减速器和 public contests: Observable<Icontest[]> = this.contestStore.select(_fromcontest.selectAll); 位。

我的目标是让一个查询获取所有文档,另一个查询仅获取符合条件的文档(过滤查询)。

contest.actions.ts的一部分

export const QUERY = '[contest] query contests';
export const QUERY_MINE = '[contest] query my contests';

[...]

// Initial Query
export class Query implements Action {
  readonly type = QUERY;
  constructor() {}
}

// Query only my contests
export class QueryMine implements Action {
  readonly type = QUERY_MINE;
  constructor() {}
}
[...]

export type contestActions =
  Query | QueryMine | Added | Modified | Removed | Update | Create | Delete | CreateSuccess | UpdateSuccess | DeleteSuccess | Failure ;
...

contest.effect.ts的一部分

@Effect()
  query$: Observable<Action> = this.actions$.ofType(contestActions.QUERY).pipe(
    switchMap(action => {
      return this.afs.collection<IContest>('contests').stateChanges();
    }),
    mergeMap((actions: DocumentChangeAction[]) =>  actions),
    map( (action: DocumentChangeAction) => {
      return {
        type: `[contest] ${action.type}`,
        payload: {
          id: action.payload.doc.id,
          ...action.payload.doc.data()
        }
      };
    })
  );

  @Effect()
  queryMine$: Observable<Action> = this.actions$.ofType(contestActions.QUERY_MINE).pipe(
    switchMap(action => {
      return this.afs.collection<Icontest>('contests', ref => {
        return ref.where('owner', '==', this._auth.cachedUser.uid);
      }).stateChanges();
    }),
    mergeMap((actions: DocumentChangeAction[]) =>  actions),
    map( (action: DocumentChangeAction) => {
      return {
        type: `[contest] ${action.type}`,
        payload: {
          id: action.payload.doc.id,
          ...action.payload.doc.data()
        }
      };
    })
  );
...

和contest.reducer.ts是:

export const contestAdapter = createEntityAdapter<IContest>();
export interface State extends EntityState<IContest> { }
export const initialState: State = contestAdapter.getInitialState();

export function contestReducer(
  state: State = initialState,
  action: actions.contestActions) {

    switch (action.type) {

      case actions.ADDED:
        return contestAdapter.addOne(action.payload, state);

      case actions.MODIFIED:
        return contestAdapter.updateOne( {
          id: action.payload.id,
          changes: action.payload,
        }, state);

      case actions.REMOVED:
      return contestAdapter.removeOne(action.payload.id, state);


      default:
      return state;
    }
  }

      // Create the default selectors
      export const getContestState = createFeatureSelector<State>('contests');

      export const {
        selectIds,
        selectEntities,
        selectAll,
        selectTotal,
      } = contestAdapter.getSelectors(getContestState);

要获取所有文档,我调用 contestStore.dispatch( new _contestActions.Query()),如果只获取我的文档,我调用 contestStore.dispatch( new _contestActions.QueryMine()) 但是,如何将每个查询的结果分配给不同的变量,比方说:

请帮忙!

您的 query$ 效果将加载所有实体。所以你不需要一个新的查询动作,但你需要一个新的选择器。

创建一个新的selector需要在state中创建一个space来存放可以引用的uid

export interface State extends EntityState<IContest> {
  currentUserUid: string;
}

和新动作:

export const LOGIN = '[contest] login';

export class Login implements Action {
  readonly type = LOGIN;
  constructor(public payload: string) {}
}

新减速机案例:

case actions.LOGIN:
  return { ...state, currentUserUid: action.payload };

新选择器:

export const getCurrentUserUid = createSelector(
  getContestState,
  state => state.currentUserUid
);

export const getMine = createSelector(
  selectAll,
  getCurrentUserUid,
  (contests, currentUserUid) =>
    contests.filter(contest => contest.owner === currentUserUid)
);

用法:

登录时调度登录操作。

public mycontests: Observable<Icontest[]> = this.contestStore.select(_fromcontest.getMine);

ps. 我建议创建一个 AuthStore。