预期的结果:我正在尝试更新Redux状态的值
问题::我最终遇到了无限循环/浏览器锁定的问题。我已经读过this 'SO' post和docs,但努力查看我要去哪里。
这是我的状态:
{ id: 0, product: TV, saleItem: false },
{ id: 1, product: Fridge, saleItem: false }
我想将其更新为
{ id: 0, product: TV, saleItem: true }
{ id: 1, product: Fridge, saleItem: false }
我的网址是:localhost:4200 /#/ 0
我正在使用选择器来获取商店中的所有商品,检查url参数并以状态返回商品。上面的网址将返回{ id: 0, product: TV, saleItem: false }
然后,我运行item = { ...item, saleItem: true };
以使减速器起火。但是,这会导致无限循环,其中console.log('before', item);
和console.log('after', item);
一遍又一遍地注销。以下是我拥有的代码以及我尝试过的一些替代方法
选择器
export const getBasketEntities = createSelector(
getBasketState,
fromItems.getBasketEntities
);
export const getSelectedItem = createSelector(
getBasketEntities,
fromRoot.getRouterState,
(entities, router): Item => {
return router.state && entities[router.state.params.id];
}
);
组件
this.store.dispatch(new fromStore.UpdateItem());
动作
export class UpdateItem implements Action {
readonly type = UPDATE_ITEM;
constructor() {}
}
效果
// update effect
@Effect()
updateItem$ = this.actions$.ofType(itemActions.UPDATE_ITEM).pipe(
switchMap(() => {
return this.store.select(fromSelectors.getSelectedItem).pipe(
map((item: Item) => {
console.log('before', item);
item = { ...item, saleItem: true };
console.log('after', item);
return new itemActions.UpdateItemSuccess(item);
}),
catchError(error => of(new itemActions.UpdateItemFail(error)))
);
})
);
减速器
case fromItems.UPDATE_ITEM_SUCCESS: {
const item: Item = action.payload;
console.log('reducer', item);
const entities = {
...state.entities,
[item.id]: item
};
return {
...state,
entities
};
}
更新:
这将导致相同的结果。
组件
onUpdate() {
this.store
.select(fromStore.getSelectedItem)
.pipe(
map((item: Item) => {
this.store.dispatch(new fromStore.UpdateItem(item));
})
)
.subscribe()
.unsubscribe();
}
效果
@Effect()
updateItem$ = this.actions$.ofType(itemActions.UPDATE_ITEM).pipe(
map((action: itemActions.UpdateItem) => action.payload),
map((item: Item) => {
return new itemActions.UpdateItemSuccess(item);
}),
catchError(error => of(new itemActions.UpdateItemFail(error)))
);
动作
export class UpdateItem implements Action {
readonly type = UPDATE_ITEM;
constructor(public payload: Item) {}
}
减速器
case fromItems.UPDATE_ITEM_SUCCESS: {
const item: Item = action.payload;
const entities = {
...state.entities,
[item.id]: { ...item, saleItem: true }
};
return {
...state,
entities
};
}
答案 0 :(得分:0)
出现无限循环的原因:
您订阅选择器->效果是创建新引用并修改项目->更新状态->这将触发选择器->依此类推……
要解决此问题:
答案 1 :(得分:0)
修复了以下问题,但这一点感觉都不好。
最好是我的效果文件中只需要一行与调度和选择器一起使用。
我在选择器上调查了withLatestFrom()
,以获得更干净的解决方案
更新:或者,我发现并使用了以下讨论:on gihub和stackblitz。我使用了选项2,并将do
替换为map
。这意味着我可以在组件this.store.dispatch(new fromStore.UpdateItem());
中运行一行,然后使用[item.id]: { ...state.entities[item.id], saleItem: true }
初始修复
this.selectedItem: Item;
onUpdate() {
this.store
.select(fromStore.getSelectedItem)
.subscribe((item: Item) => this.selectedItem = item )
.unsubscribe();
this.store.dispatch(new fromStore.UpdateItem(this.selectedItem));
}
StackBlitz方法1 -将tap
替换为map
。清洁工
@Effect()
updateItem$ = this.actions$.ofType(itemActions.UPDATE_ITEM).pipe(
withLatestFrom(this.store.pipe(select(fromSelectors.getSelectedItem))),
map(([type, item]: Array<any>) => {
console.log('in effect', item);
return new itemActions.UpdateItemSuccess(item);
}),
catchError(error => of(new itemActions.UpdateItemFail(error)))
);