我必须告诉你我已经疯了。我尝试使用AngularFire2(v.5)从Firebase获取数据,然后在@ngrx / effects上使用它并将其存储在@ngrx / store上。好吧,因为我需要带键的数据,我的效果代码如下所示:
spaces.effects.ts
@Effect()
getSpaces$ = this.actions$.ofType(SpacesActions.GET_SPACES_REQUEST)
.switchMap((action: SpacesActions.GetSpacesRequest) => {
return this.afs.list<Space>('/spaces').snapshotChanges()
.switchMap(actions => {
console.log('action is ', actions);
return actions.map(space => {
const $key = space.payload.key;
const data: Space = { $key, ...space.payload.val() };
console.log('snapshot is: ', data);
return new SpacesActions.GetSpacesSuccess(data);
});
}
);
我的行动&#34;随附数据和密钥,然后我得到每个项目的密钥,因为这样我就可以轻松更新和删除项目。我的数据库有3个项目,3个键。如果我运行此代码并记录它,首先我可以看到1个数组中的所有项目及其有效负载,而第二个日志我将每个有效负载视为快照。
当我调用GetSpacesSuccess时,我想发送我得到的所有快照(带有密钥和项目)然后存储它。我现在做的方式是3次调度此动作,我只能在屏幕上看到2个项目,因为第一个项目被第二个项目覆盖。
所以,有两个问题:是否有更简单的方法从firebase获取项目的密钥,然后用@ngrx存储它们?如果没有,我错误的是我的第一个项目被覆盖并且我的行动被派遣了3次?
拜托,我在学习的过程中尽我所能。谢谢!
spaces.reducers.ts
case SpacesActions.GET_SPACES_REQUEST:
return {
state,
spaces: null,
loading: true
};
case SpacesActions.GET_SPACES_SUCCESS:
return {
...state,
...action.payload,
spaces: [state, action.payload],
loading: false
};
spaces.actions.ts
export class GetSpacesRequest implements Action {
readonly type = GET_SPACES_REQUEST;
}
export class GetSpacesSuccess implements Action {
readonly type = GET_SPACES_SUCCESS;
constructor(public payload: Space) {} <<<<<HERE I'D LIKE TO GET THE FULL ARRAY WITH EACH KEY
}
答案 0 :(得分:1)
感谢@ AndreaM16提供最完整的答案。我经历了夜晚的工作,最后我做了不同的事情。实际上,在学习过程中,我们会犯错误以获取知识。可能你的解决方案比我的好,我会研究,谢谢。如果可能的话,我希望听到您对我的解决方案的评论。
最后,在阅读了大量文档后,我的效果现在就是这个,但我没有任何错误捕获器:
private spacesList = 'spaces/';
@Effect()
getSpaces$ = this.actions$.ofType(SpacesActions.GET_SPACES_REQUEST)
.switchMap(payload => this.afs.list(this.spacesList).snapshotChanges()
.map(spaces => {
return spaces.map(
res => {
const $key = res.payload.key;
const space: Space = {$key, ...res.payload.val()};
return space;
}
);
})
.map(res =>
new SpacesActions.GetSpacesSuccess(res)
));
<强>减速强>
case SpacesActions.GET_SPACES_REQUEST:
return Object.assign({}, state, {
spaces: null,
loading: true
});
case SpacesActions.GET_SPACES_SUCCESS:
return Object.assign({}, state, {
spaces: action.payload,
loading: false
});
操作强>
export class GetSpacesRequest implements Action {
readonly type = GET_SPACES_REQUEST;
}
export class GetSpacesSuccess implements Action {
readonly type = GET_SPACES_SUCCESS;
constructor(public payload: Space[]) {}
}
而且,在我的组件中,我需要列表:
constructor(private store: Store<fromSpaces.FeatureState>) {}
ngOnInit() {
this.store.dispatch(new SpacesActions.GetSpacesRequest());
this.spacesState = this.store.select('spaces');
}
答案 1 :(得分:0)
如果我正确理解了您的问题,您希望为每个项目存储也存储其密钥。您正在寻找Map。
我会按如下方式构建您的功能。
<强> spaces.actions.ts 强>:
加载空间不需要有效负载,而成功只有一个Space数组。我认为您应该在减速机中构建Map<string,Space>
(string
是您的密钥)。
import { Action } from '@ngrx/store';
/** App Models **/
import { Space } from './space.model';
export const GET_SPACES = '[Spaces] Spaces get';
export const GET_SPACES_SUCCESS = '[Start] Spaces get - Success';
export class GetSpacesAction implements Action {
readonly type = GET_SPACES;
}
export class GetSpacesActionSuccess implements Action {
readonly type = GET_SPACES_SUCCESS;
constructor(public payload: Space[]) {}
}
export type All
= GetSpacesAction
| GetSpacesActionSuccess;
<强> spaces.effects.ts 强>:
我假设你只需要一个方法来获取空格。如果您需要做其他事情,只需编辑这段代码即可。 spaceService.getSpaces()
应该只返回一个Spaces数组。因此,创建一个新的Space
模型,并在您的服务上将每个json条目映射到new Space()
。
import { Injectable } from '@angular/core';
import { Actions, Effect } from '@ngrx/effects';
/** rxjs **/
import {map} from 'rxjs/operators/map';
import {mergeMap} from 'rxjs/operators/mergeMap';
import {catchError} from 'rxjs/operators/catchError';
/** ngrx **/
import * as spacesActions from './spaces.actions';
/** App Services **/
import { SpacesService } from './spaces.service';
@Injectable()
export class SpacesEffects {
@Effect() getSpaces$ = this.actions$
.ofType(spaceActions.GET_SPACES)
.pipe(
mergeMap(() => {
return this.spaceService.getSpaces()
.pipe(
map((spaces) => {
return new spacesActions.GetSpacesActionSuccess(spaces);
}),
catchError((error: Error) => {
// Handle erro here
})
);
})
)
;
constructor(private spacesService: SpacesService, private actions$: Actions) { }
}
<强> spaces.reducer.ts 强>
在这里,您可以构建地图,还可以创建一个新动作来返回,例如,给定其键的空间。我不认为你在这里需要任何加载参数,我猜你在视图中使用它来进行一些加载处理,只需在你的视图中使用AsyncPipe并处理加载动画并检查*ngIf
是否存在空间与否。
/** ngrx **/
import {createFeatureSelector} from '@ngrx/store';
import {createSelector} from '@ngrx/store';
import * as spacesActions from './spaces.actions';
export type Action = spacesActions.All;
/** App Models **/
import { Space } from './space.model';
export interface SpaceState {
keySpaces: Map<string, Space>;
spaces: Space[];
keys: string[];
}
export const initialState: SpaceState = {
keySpaces: new Map<string, Space>(),
spaces: [],
keys: []
};
// Selectors
export const selectSpace = createFeatureSelector<SpaceState>('space');
export const getKeySpaces = createSelector(selectSpace, (state: StartState) => {
return state.keySpaces;
});
export const getSpaces = createSelector(selectSpace, (state: SpaceState) => {
return state.spaces;
});
export const getKeys = createSelector(selectSpace, (state: SpaceState) => {
return state.keys;
});
export function spacesReducer(state: SpaceState = initialState, action: Action): SpaceState {
switch (action.type) {
case startActions.GET_SPACES_SUCCESS:
// Since we return this from effect
const fetchedSpaces = action.payload;
const fetchedKeys = [];
const keySpacesMap = new Map<string, Space>();
fetchedSpaces.forEach( (space: Space) => {
fetchedkeys = fetchedKeys.concat(space.key);
keySpacesMap.set(space.key, new Space(space));
}
returns {
...state,
keySpaces: keySpacesMap,
spaces: fetchedSpaces,
keys: fetchedkeys
}
default: {
return state;
}
}
}
最后,你应该能够在你的组件中获得这样的参数,如:
. . .
keySpaces$ = Observable<Map<string, Space>>;
spaces$ = Observable<Array<Space>>;
keys$ = Observable<Array<string>>;
constructor(private _store: Store<AppState>) {
this.keySpaces$ = this._store.select(getKeySpaces);
this.space$s = this._store.select(getSpaces);
this.keys$ = this._store.select(getKeys);
}
. . .
ngOnInit() {
this._store.dispatch(new spacesActions.GetSpacesAction);
}
. . .
当然,将新状态添加到AppState
:
. . .
export interface AppState {
. . .
space: SpaceState;
}