英文:
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 "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;
}
}
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<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;
}
}
Thats my 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>
And this is the parent component shelf.component.html in which the problematic component is created:
<div class="container">
<div *ngFor="let product of products | async">
<app-shelf-item [product]="product"></app-shelf-item>
</div>
</div>
And it's shelf.component.ts file
:
export class ShelfComponent implements OnInit {
@Input() products: Observable<Product[]>;
constructor(private store: Store<State>) {}
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 'rxjs/operators';
this.store
.pipe(
select(state => state.shoppingCartReducer.Entries}),
take(1),
).subscribe(data => {
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 => state.shoppingCartReducer.Entries)
.subscribe(data => this.dispatchNewCartEntry(data));
that means that each times shoppingcart entries change , dispatch will be triggered inside the subscription
答案3
得分: 0
我遇到了类似的问题 - 完全是我的错 - 减速器和效果处于无限循环中。花了几个小时进行调试,结果发现我在复制粘贴时重复了动作名称(令人作呕 >.<)。
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论