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())
但是,如何将每个查询的结果分配给不同的变量,比方说:
public contests: Observable<Icontest[]> = this.contestStore.select(_fromcontest.selectAll );
public mycontests: Observable<Icontest[]> = this.contestStore.select( ????? );
?
请帮忙!
您的 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。
我正在努力使用 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())
但是,如何将每个查询的结果分配给不同的变量,比方说:
public contests: Observable<Icontest[]> = this.contestStore.select(_fromcontest.selectAll );
public mycontests: Observable<Icontest[]> = this.contestStore.select( ????? );
?
请帮忙!
您的 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。