4
votes

I have a problem where my computed properties (that basically just calls a store getter with an id) does not get re-computed when the store changes. Anyone know why?

Product computed (isInCart is the relavant one, the other just show that state changes works)

isInCart() {
    var isInCart = this.$store.getters['shoppingCart/isInCart'](this.product.id);
    return isInCart;
  }

Vuex store

const getters = {
  count: state => state.items.length,
  hasItems: state => !!state.items.length,
  isInCart(state) {
    return id => state.items.findIndex((item) => {
      return item.productId === id; 
    }) > -1;
  }
}

and state change is done by a mutation like this:

setCart(state, cart) {
    state.items = cart.items;
  },

The initial call to the getter works as expected. It's just that when the state is changed it is not ran again. The other getters "hasItem" and "count" work as expected.


I also tried in my component to put the function directly into the computed like so:

computed: {
     ...mapState({
        isInCart(state) {
          var id = this.product.id;
          return !!state.shoppingCart.items.filter(item => item.productId === id).length
        }
      })
    },
1
I would bet it's because of the dynamic access of the getter (['shoppingCart/isInCart']) - how would it map it? :) Also I don't clearly see the logic - you are basically calling a method (which is a getter) and you want to trigger the computed property when the store changes? What in the store can change here, as you are calling a method from this store?Andrey Popov
When you add a product the store does an API call and re-fetches everything. Meaning setCart is called with a new list of items: state.item has 1 more item in it's array. See that I have some code in the wrong place, fixed now.Todilo
isInCart is a computed property, right? I would think because of the dynamic getter as I said before - try simplifying it. Then I would suggest using mapGetters as described in the documentation. Then it would also be good if you watch for state changes and then call the getter, as it needs an argument and I'm not sure it can be reactive, because the argument can change as well :)Andrey Popov
yes it is. I added a new "version" of the isInCart using mapState to circumvent the getter reactiveness with parameter problem. See at the bottom.(still doesn't work though) The computed is used in an v-if="isInCart" if that matters.Todilo
I don't get this mapped state. Here's what is working with me (just tested it): computed: { ...mapGetters(['items']) }, watch: { items () { console.log('items updated') } }Andrey Popov

1 Answers

2
votes

This is because the getter returns a function. Each state that a getter dependent on is an observer. It observes the change of these dependencies. Any change can trigger the getter to run. But, if the getter just returns a function, you won't get the result of this function. Instead, you get a result of a function with updated value.