简体   繁体   English

为什么我的 *ngFor 对 ngrx 状态变化做出反应,但我的 subscribe 方法只执行一次

[英]Why is my *ngFor reacting to ngrx state changes but my subscribe method does only once

In my Application I have a ngrx store which contains an array of objects.在我的应用程序中,我有一个 ngrx 存储,其中包含一组对象。 In my constructor I am selecting the array and calling a method (onProductEntriesLoaded) which sets a variable to this array.在我的构造函数中,我选择了数组并调用了一个方法 (onProductEntriesLoaded),该方法为该数组设置了一个变量。 In the html Code there is a *ngFor Loop that iterates through this variable and displays them.在 html 代码中有一个 *ngFor 循环,它遍历这个变量并显示它们。 The method which sets the variable does also call another method which calculates a sum.设置变量的方法也会调用另一个计算总和的方法。 However each time a add elements to this array in the state, the content is displayed correctly in the *ngFor loop.但是,每次在状态中向此数组添加元素时,内容都会在 *ngFor 循环中正确显示。 But the method which is setting the variable to the array is not called.但是没有调用将变量设置为数组的方法。 It is only called at initialization.它仅在初始化时调用。 I thought that every part of the application which is subscribing to the state is loaded again whenever the state changes.我认为订阅状态的应用程序的每个部分都会在状态发生变化时再次加载。 Even if it is a constructor.即使它是一个构造函数。 However it doesn't seem to be like that.然而,它似乎并非如此。 Could someone please explain me this behavior.有人可以向我解释这种行为。

This is part of my cart.component.html这是我的 cart.component.html 的一部分

 <div id="middle">
      <div class="entries">
        <div *ngFor="let entry of productEntries">
          <img
            *ngIf="!entry.product.image"
            src="../../../assets/img/esansBottles Kopie.png"
          />
          <img
            *ngIf="entry.product.image"
            src="../../../assets/img/{{ entry.product.image }}"
          />
          {{ entry.product.title }}
          {{ entry.variation.option }}
          {{ entry.variation.price }}
          {{ entry.amount }}
        </div>
      </div>
    </div>
    <div id="bottom">
      <div>Summe {{ sumOfCart }} €</div>
      <button>Zur Kasse</button>
    </div>

And that's basically the cart.component.ts file这基本上就是cart.component.ts文件

export class CartComponent implements OnInit {
  productEntries: ShoppingCartEntry[];
  sumOfCart: number;

  constructor(private store: Store<State>) {
    this.store
      .select(state => state.shoppingCartReducer.Entries)
      .subscribe(data => this.onProductEntriesLoaded(data));
  }

  ngOnInit() {}

  onProductEntriesLoaded(productEntries: ShoppingCartEntry[]) {
    console.log("onProductEntreisLoaded called");
    this.productEntries = productEntries;
    console.log(productEntries);
    console.log("next calculate sum");
    this.calculateSum(productEntries);
    console.log("after calculate sum");
  }

  calculateSum(shoppingCartEntries: ShoppingCartEntry[]) {
    console.log("calculate sum called");
    /*let sum = 0.0;
    console.log(shoppingCartEntries);
    if (shoppingCartEntries) {
      shoppingCartEntries.forEach(element => {
        sum = element.amount * element.variation.price + sum;
      });
    }
    this.sumOfCart = sum;*/
  }

And that's one part of my reducer.ts file这是我的 reducer.ts 文件的一部分


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: addEntryToCart(state.Entries, action.payload)
      };
    default:
      return state;
  }
}

function addEntryToCart(
  currentEntries: ShoppingCartEntry[],
  entry: ShoppingCartEntry
): ShoppingCartEntry[] {
  //if currentEntries is null return empty array
  if (currentEntries) {
    // if entry is null return currentEntries
    if (entry) {
      // check if currentEntries contains entry
      let index = currentEntries.findIndex(
        x => x.product === entry.product && x.variation === entry.variation
      );
      if (index === -1) {
        let newEntries = currentEntries;
        newEntries.push(entry);
        return newEntries;
      } else {
        currentEntries[index].amount += entry.amount;
        return currentEntries;
      }
    } else {
      return currentEntries;
    }
  } else {
    return [];
  }
}


The problem was caused in my reducer function.问题是由我的减速器功能引起的。 After removing the function call to addEntryToCart inside my reducer and implementing the functionality within the reducer the problem was solved.在我的减速器中删除对 addEntryToCart 的函数调用并在减速器中实现功能后,问题就解决了。 I still don't understand why calling a function caused the problem.我仍然不明白为什么调用函数会导致问题。

Thats how I solved it:我就是这样解决的:

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":
      let contains = state.Entries.findIndex(
        entry =>
          entry.product === action.payload.product &&
          entry.variation === action.payload.variation
      );
      if (contains === -1) {
        return {
          ...state,
          Entries: [...state.Entries.concat(action.payload)]
        };
      } else {
        return {
          ...state,
          Entries: [
            ...state.Entries.map(entry =>
              entry.product === action.payload.product &&
              entry.variation === action.payload.variation
                ? {
                    product: entry.product,
                    variation: entry.variation,
                    amount: entry.amount + action.payload.amount
                  }
                : entry
            )
          ]
        };
      }

    default:
      return state;
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM