NX + NGRX TypeError: entities is not iterable. Why?
NX + NGRX TypeError: entities is not iterable. Why?
我过去使用过 Ngrx,没有遇到任何问题。现在我第一次尝试使用实体,但它根本不起作用。
我在 NX 工作区中有一个 Angular9+ 应用程序调用来自服务的一些模拟数据。
谁能告诉我怎么了?我想不明白。
(这个很长post)
动作文件:
....
export const loadSheetData = createAction('[SheetData] Load SheetData');
export const loadSheetDataSuccess = createAction(
'[SheetData] Load SheetData Success',
props<{ sheetData: SheetDataEntity[] }>()
);
....
效果文件
....
@Injectable()
export class SheetDataEffects {
loadSheetData$ = createEffect(() =>
this.actions$.pipe(
ofType(SheetDataActions.loadSheetData),
fetch({
run: (action) => {
return this.bottomSheetSvc.getSheetData().pipe(
tap((obj) =>
catchError(error => of(new Error('Effect failed') ) ),
map((data) => SheetDataActions.loadSheetDataSuccess({ sheetData: data}) ) );
onError: (action, error) => {
return SheetDataActions.loadSheetDataFailure({ error });
},
})
)
);
....
模型文件
export interface SheetDataEntity {
id: string | number; // Primary ID
info: string;
link: string;
icon?: string;
isDisabled?: boolean;
}
减速器文件
export const SHEETDATA_FEATURE_KEY = 'sheetData';
export interface State extends EntityState<SheetDataEntity> {
selectedId?: string | number; // which SheetData record has been selected
loaded: boolean; // has the SheetData list been loaded
error?: string | null; // last none error (if any)
}
export interface SheetDataPartialState {
readonly [SHEETDATA_FEATURE_KEY]: State;
}
export const sheetDataAdapter: EntityAdapter<SheetDataEntity> = createEntityAdapter<
SheetDataEntity
>();
export const initialState: State = sheetDataAdapter.getInitialState({
// set initial required properties
entities: {
0: {}
},
loaded: false,
});
const sheetDataReducer = createReducer(
initialState,
on(SheetDataActions.loadSheetData, (state) => ({
...state,
loaded: false,
error: null,
})),
on(SheetDataActions.loadSheetDataSuccess, (state, { sheetData }) =>
{
console.log('TEMP1:', state, sheetData);
let temp = sheetDataAdapter.setAll(sheetData, { ...state, loaded: true })
console.log('TEMP2:', temp);
return temp;
}
),
on(SheetDataActions.loadSheetDataFailure, (state, { error }) => ({
...state,
error,
}))
);
export function reducer(state: State | undefined, action: Action) {
console.log('SHEET REDUCER::', state, action);
return sheetDataReducer(state, action);
}
选择器文件
....
export const getAllSheetData = createSelector(
getSheetDataState,
(state: State) => selectAll(state)
);
....
服务数据
dummyData: any = {
ids: [5, 4, 3, 2, 1],
entities: {
1: {
id: 1,
info: 'test info 1',
link: '/test1',
icon: 'test icon 1',
isDisabled: false
},
2: {
id: 2,
info: 'test info 2',
link: '/test2',
icon: 'test icon 2',
isDisabled: false
},
3: {
id: 3,
info: 'test info 3',
link: '/test3',
icon: 'test icon 3',
isDisabled: false
},
4: {
id: 4,
info: 'test info 4',
link: '/test4',
icon: 'test icon 4',
isDisabled: false
},
5: {
id: 5,
info: 'test info 5',
link: '/test5',
icon: 'test icon 5',
isDisabled: false
}
}
};
组件文件
sheetData$: Observable<SheetDataEntity[]>;
constructor(
private store: Store<State>,
) {
this.sheetData$ = this.store.pipe( select( selectors.getAllSheetData ) );
}
ngOnInit(): void {
this.store.dispatch( actions.loadSheetData() );
}
模板文件
<sheet-item
*ngFor="let item of (sheetData$ | async)"
[item]="item"
(onUpdateSelectedLink)="updateSelectedLink($emit)">
</sheet-item>
耶!终于成功了。是一个愚蠢的错误!我将服务模拟数据修改为一个普通的项目数组。然后将其传递到“成功操作”中。尝试学习多个使用不同 Angular 版本和代码风格的教程时感到困惑。
感谢@derekkite / @RoboZoom(在 Gitter 中),你让我走上了正确的道路。 :)
run: (action) => {
return this.bottomSheetSvc.getSheetData().pipe(
tap((obj) => console.log('Effect: switch:', obj)),
catchError(error => of(new Error('Effect failed') ) ),
map((dataObj) => SheetDataActions.loadSheetDataSuccess({ sheetData: dataObj.data }) ) );
},
我过去使用过 Ngrx,没有遇到任何问题。现在我第一次尝试使用实体,但它根本不起作用。
我在 NX 工作区中有一个 Angular9+ 应用程序调用来自服务的一些模拟数据。
谁能告诉我怎么了?我想不明白。 (这个很长post)
动作文件:
....
export const loadSheetData = createAction('[SheetData] Load SheetData');
export const loadSheetDataSuccess = createAction(
'[SheetData] Load SheetData Success',
props<{ sheetData: SheetDataEntity[] }>()
);
....
效果文件
....
@Injectable()
export class SheetDataEffects {
loadSheetData$ = createEffect(() =>
this.actions$.pipe(
ofType(SheetDataActions.loadSheetData),
fetch({
run: (action) => {
return this.bottomSheetSvc.getSheetData().pipe(
tap((obj) =>
catchError(error => of(new Error('Effect failed') ) ),
map((data) => SheetDataActions.loadSheetDataSuccess({ sheetData: data}) ) );
onError: (action, error) => {
return SheetDataActions.loadSheetDataFailure({ error });
},
})
)
);
....
模型文件
export interface SheetDataEntity {
id: string | number; // Primary ID
info: string;
link: string;
icon?: string;
isDisabled?: boolean;
}
减速器文件
export const SHEETDATA_FEATURE_KEY = 'sheetData';
export interface State extends EntityState<SheetDataEntity> {
selectedId?: string | number; // which SheetData record has been selected
loaded: boolean; // has the SheetData list been loaded
error?: string | null; // last none error (if any)
}
export interface SheetDataPartialState {
readonly [SHEETDATA_FEATURE_KEY]: State;
}
export const sheetDataAdapter: EntityAdapter<SheetDataEntity> = createEntityAdapter<
SheetDataEntity
>();
export const initialState: State = sheetDataAdapter.getInitialState({
// set initial required properties
entities: {
0: {}
},
loaded: false,
});
const sheetDataReducer = createReducer(
initialState,
on(SheetDataActions.loadSheetData, (state) => ({
...state,
loaded: false,
error: null,
})),
on(SheetDataActions.loadSheetDataSuccess, (state, { sheetData }) =>
{
console.log('TEMP1:', state, sheetData);
let temp = sheetDataAdapter.setAll(sheetData, { ...state, loaded: true })
console.log('TEMP2:', temp);
return temp;
}
),
on(SheetDataActions.loadSheetDataFailure, (state, { error }) => ({
...state,
error,
}))
);
export function reducer(state: State | undefined, action: Action) {
console.log('SHEET REDUCER::', state, action);
return sheetDataReducer(state, action);
}
选择器文件
....
export const getAllSheetData = createSelector(
getSheetDataState,
(state: State) => selectAll(state)
);
....
服务数据
dummyData: any = {
ids: [5, 4, 3, 2, 1],
entities: {
1: {
id: 1,
info: 'test info 1',
link: '/test1',
icon: 'test icon 1',
isDisabled: false
},
2: {
id: 2,
info: 'test info 2',
link: '/test2',
icon: 'test icon 2',
isDisabled: false
},
3: {
id: 3,
info: 'test info 3',
link: '/test3',
icon: 'test icon 3',
isDisabled: false
},
4: {
id: 4,
info: 'test info 4',
link: '/test4',
icon: 'test icon 4',
isDisabled: false
},
5: {
id: 5,
info: 'test info 5',
link: '/test5',
icon: 'test icon 5',
isDisabled: false
}
}
};
组件文件
sheetData$: Observable<SheetDataEntity[]>;
constructor(
private store: Store<State>,
) {
this.sheetData$ = this.store.pipe( select( selectors.getAllSheetData ) );
}
ngOnInit(): void {
this.store.dispatch( actions.loadSheetData() );
}
模板文件
<sheet-item
*ngFor="let item of (sheetData$ | async)"
[item]="item"
(onUpdateSelectedLink)="updateSelectedLink($emit)">
</sheet-item>
耶!终于成功了。是一个愚蠢的错误!我将服务模拟数据修改为一个普通的项目数组。然后将其传递到“成功操作”中。尝试学习多个使用不同 Angular 版本和代码风格的教程时感到困惑。 感谢@derekkite / @RoboZoom(在 Gitter 中),你让我走上了正确的道路。 :)
run: (action) => {
return this.bottomSheetSvc.getSheetData().pipe(
tap((obj) => console.log('Effect: switch:', obj)),
catchError(error => of(new Error('Effect failed') ) ),
map((dataObj) => SheetDataActions.loadSheetDataSuccess({ sheetData: dataObj.data }) ) );
},