简体   繁体   中英

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. In my constructor I am selecting the array and calling a method (onProductEntriesLoaded) which sets a variable to this array. In the html Code there is a *ngFor Loop that iterates through this variable and displays them. 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. 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

 <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

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


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. 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;
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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