代码之家  ›  专栏  ›  技术社区  ›  fidev

正在更新处于redux状态的项,导致无限循环/浏览器锁定

  •  0
  • fidev  · 技术社区  · 6 年前

    预期结果: 我正在尝试更新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 }
    

    我的url是:localhost:4200/#/0

    我正在使用选择器获取我的存储中的所有项,检查url参数并返回状态中的项。上面的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
      };
    }
    
    2 回复  |  直到 6 年前
        1
  •  0
  •   timdeschryver    6 年前

    你有无限循环的原因是:

    您订阅了选择器->实际上您创建了一个新的ref并修改了项->您更新了状态->这将触发选择器->等

    要解决此问题:

    • 不要更新效果中的项目。
    • 在更新操作中将所选项目设置为负载
    • 更新reducer中的项(在示例中不需要成功或失败操作)
        2
  •  0
  •   fidev    6 年前

    修正了下面的问题,但是感觉一点也不好。 最好我只想在我的效果文件中有一行我的调度和选择器。 我已经调查过了 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 具有 地图 . 保洁员

    @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)))
      );