为什么我的ngrx动作引起了无休止的循环?

huangapple go评论85阅读模式
英文:

Why is my ngrx action causing an endless loop?

问题

这是您提供的代码的翻译:

我有一个简单的操作我想在状态中的数组中添加一些对象不知何故它陷入了无限循环我还没有弄清楚为什么会发生这种情况我对ngrx和Angular都很陌生我做错了什么该操作在单击按钮后触发该按钮调用了`shelf-item.component.ts`中的`onAddToCartButtonClicked()`函数

这是我的`reducer.ts`中的减速器

```javascript
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();
    }
  }

  // 其他方法...

}

这是我的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>
<!-- 其他HTML内容... -->
<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文件:

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

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

  ngOnInit() {}
}

希望这些翻译有助于您更好地理解您的代码和问题。如果您需要进一步的帮助或解释,请随时提出。

英文:

I have one simple action in which I want to add some object into an array in my state. Somehow it runs into an endless loop. I couldn't figure out yet why it is happening. I am new to ngrx and Angular. What am I doing wrong? The action is fired after clicking on the button, which is calling following function onAddToCartButtonClicked() in shelf-item.component.ts

This is my reducer in reducer.ts:

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


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

This is basically my shelf-item-component.ts

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

  constructor(private store: Store&lt;State&gt;) {}

  ngOnInit() {
    if (this.product &amp;&amp; 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: &quot;SET_LOADING&quot; });
    this.store
      .select(state =&gt; state.shoppingCartReducer.Entries)
      .subscribe(data =&gt; this.dispatchNewCartEntry(data));
  }

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

  constructNewCartEntry(entries: ShoppingCartEntry[]): ShoppingCartEntry {
    let matchingEntry = entries.find(
      entry =&gt;
        entry.product.id === this.product.id &amp;&amp;
        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 &amp;&amp; this.product.variations.length &gt; 0) {
      return true;
    } else {
      return false;
    }
  }

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

Thats my shelf-item-component.html

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

And this is the parent component shelf.component.html in which the problematic component is created:

&lt;div class=&quot;container&quot;&gt;
  &lt;div *ngFor=&quot;let product of products | async&quot;&gt;
    &lt;app-shelf-item [product]=&quot;product&quot;&gt;&lt;/app-shelf-item&gt;
  &lt;/div&gt;
&lt;/div&gt;

And it's shelf.component.ts file:

export class ShelfComponent implements OnInit {
  @Input() products: Observable&lt;Product[]&gt;;

  constructor(private store: Store&lt;State&gt;) {}

  ngOnInit() {}
}

I am really stuck and don't understand it :/

答案1

得分: 3

如Fateh提到的,它将被触发并且值将被订阅。如果要在订阅商店选择器时仅触发一次此操作,您可以链接上述语句使用RxJS take() 运算符。

此运算符将确保仅由源可观察对象发出给 take() 运算符的指定计数值。

import { take } from 'rxjs/operators';

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

As Fateh mentioned, it will be triggered and the values will be subscribed. If this action is to be fired once upon subscribing to the store selector, you may chain the above statement the RxJS take() operator.

This operator will ensure that only the specified count values supplied to be take() operator will be emitted by the source observable.

import { take } from &#39;rxjs/operators&#39;;

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

答案2

得分: 0

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

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

这意味着每当购物车条目更改时,将在订阅内触发分派操作。

英文:

it's normal, You are subscribing to shopping cart entities here

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

that means that each times shoppingcart entries change , dispatch will be triggered inside the subscription

答案3

得分: 0

我遇到了类似的问题 - 完全是我的错 - 减速器和效果处于无限循环中。花了几个小时进行调试,结果发现我在复制粘贴时重复了动作名称(令人作呕 >.<)。

英文:

I had a similar problem - completely my fault - the reducer and effects were in an infinite cycle. Spent hours debugging, only to find out that I had duplicated the action names in a copy-paste-cident (sickening >.<)

为什么我的ngrx动作引起了无休止的循环?

huangapple
  • 本文由 发表于 2020年1月6日 23:57:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/59615190.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定