typescript 为什么我的ngrx操作会导致无限循环?

envsm3lx  于 2023-01-06  发布在  TypeScript
关注(0)|答案(3)|浏览(159)

我有一个简单的动作,我想在我的状态下添加一些对象到一个数组中。不知何故,它运行到一个死循环。我还不知道为什么会发生这种情况。我是ngrx和Angular的新手。我做错了什么?这个动作是在单击按钮后触发的,它调用了shelf-item.component.ts中的以下函数onAddToCartButtonClicked()
这是我在reducer.ts中的减速器:

export type ShoppinCartState = {
  CartIsOpen: boolean;
  Entries: ShoppingCartEntry[];
};

export function shoppingCartReducer(
  state: ShoppinCartState = { CartIsOpen: false, Entries: [] },
  action: ShoppingCartAction
) {
  switch (action.type) {
    case "CART_TOGGLE":
      return {
        ...state,
        CartIsOpen: !state.CartIsOpen
      };
    case "CART_CLOSE":
      return {
        ...state,
        CartIsOpen: false
      };
    case "CART_ADD_ENTRY":
      return {
        ...state,
        Entries: [...state.Entries.concat(action.payload)]
      };
    default:
      return state;
  }
}

这基本上就是我的shelf-item-component.ts

export class ShelfItemComponent implements OnInit {
  @Input() product: Product;
  selectedOption: ProductVariant;
  isInputMissing: boolean = false;

  constructor(private store: Store<State>) {}

  ngOnInit() {
    if (this.product && this.product.variations) {
      if (this.product.variations.length === 1) {
        this.selectedOption = this.product.variations[0];
      }
    }
  }

  onAddToCartButtonClicked() {
    if (this.isValid()) {
      this.addProductToCart();
    }
  }

  addProductToCart() {
    this.store.dispatch({ type: "SET_LOADING" });
    this.store
      .select(state => state.shoppingCartReducer.Entries)
      .subscribe(data => this.dispatchNewCartEntry(data));
  }

  dispatchNewCartEntry(entries: ShoppingCartEntry[]) {
    this.store.dispatch(
      new AddShoppingCartEntry(this.constructNewCartEntry(entries))
    );
    this.store.dispatch({ type: "UNSET_LOADING" });
  }

  constructNewCartEntry(entries: ShoppingCartEntry[]): ShoppingCartEntry {
    let matchingEntry = entries.find(
      entry =>
        entry.product.id === this.product.id &&
        entry.variation === this.selectedOption
    );
    let amount = matchingEntry ? matchingEntry.amount + 1 : 1;
    return {
      product: this.product,
      amount: amount,
      variation: this.selectedOption
    };
  }

  isValid(): boolean {
    if (this.isOptionToBeSelected()) {
      if (this.selectedOption) {
        this.isInputMissing = false;
        return true;
      } else {
        this.isInputMissing = true;
        return false;
      }
    }
    return true;
  }

  isOptionToBeSelected(): boolean {
    if (this.product && this.product.variations.length > 0) {
      return true;
    } else {
      return false;
    }
  }

  onOptionSelected(option: ProductVariant) {
    this.selectedOption = option;
    this.isInputMissing = false;
  }
}

那是我的shelf-item-component.html

<h3>{{ product.title }}</h3>
<img *ngIf="!product.image" src="../../../assets/img/esansBottles Kopie.png" />
<div
  [ngClass]="{ inValid: isInputMissing }"
  *ngIf="product.variations.length > 1"
>
  <form>
    <div class="variation" *ngFor="let variation of product.variations">
      <label>
        <input
          type="radio"
          name="variation"
          value="variation"
          (change)="onOptionSelected(variation)"
        />
        {{ variation.option }} {{ variation.price }} €</label
      >
    </div>
  </form>
</div>
<div *ngIf="product.variations.length === 1">
  <div *ngIf="selectedOption">
    {{ selectedOption.option }} {{ selectedOption.price }}€
  </div>
</div>
<div>
  <p>{{ product.description }}</p>
</div>
<div (click)="onAddToCartButtonClicked()" class="addToCartButton">
  In den Warenkorb
</div>

这是父组件shelf.component.html,在其中创建了有问题的组件:

<div class="container">
  <div *ngFor="let product of products | async">
    <app-shelf-item [product]="product"></app-shelf-item>
  </div>
</div>

它是shelf.component.ts file

export class ShelfComponent implements OnInit {
  @Input() products: Observable<Product[]>;

  constructor(private store: Store<State>) {}

  ngOnInit() {}
}

我真的卡住了,不明白:/

nnsrf1az

nnsrf1az1#

正如Fateh提到的,它将被触发,并且值将被订阅。如果这个操作在订阅存储选择器时被触发一次,您可以将上面的语句链接到RxJS take()操作符。
该操作符将确保只有提供给take()操作符的指定计数值才会由源观察对象发出。

import { take } from 'rxjs/operators';

this.store
  .pipe(
    select(state => state.shoppingCartReducer.Entries}),
    take(1),
  ).subscribe(data => {
    this.dispatchNewCartEntry(data);
  });
cs7cruho

cs7cruho2#

这是正常的,您在此处订阅购物车实体

this.store
  .select(state => state.shoppingCartReducer.Entries)
  .subscribe(data => this.dispatchNewCartEntry(data));

这意味着每次购物车条目更改时,将在订阅内触发调度

n9vozmp4

n9vozmp43#

我也遇到过类似的问题--完全是我的错--减速器和效果都在无限循环中。花了几个小时调试,才发现我在复制粘贴cident中复制了动作名称(令人作呕〉.〈)

相关问题