Home > Blockchain >  Reactivity doesn't work using state in VueJS and Vuex
Reactivity doesn't work using state in VueJS and Vuex

Time:12-09

I have an increment field, I do everything right. Updates the states in the vue dev tols, etc... However it doesn't update the values ​​of the component's buttons there. I've tried everything already. But the reactivity is not happening in this case.

Component buttons

I'll leave a part of the VUEX code to see if it helps:

export default {
  namespaced: true,
  state: {   
    productsInBag: []
  },  
  mutations: {     
    ADD_TO_BAG(state, product) {
      state.productsInBag.push(product);
      localStorage.setItem("productsInBag", JSON.stringify(state.productsInBag))
    },
    REMOVE_FROM_BAG(state, productId) {
      let updatedBag = state.productsInBag.filter(item => productId != item.id)
      state.productsInBag = updatedBag     
    },
    DECREASE_PRODUCT(state, product) {     
      let itemIndex = state.productsInBag.findIndex(x => x.id === product.id)       
      state.productsInBag[itemIndex].quantity--   
    },
    INCREASE_PRODUCT(state, productId) {
      state.productsInBag.find(item => item.id === productId).quantity        
    }
      
  },
  actions: {
    addToBag ({ commit }, payload) {          
      commit('ADD_TO_BAG', payload.product)
    },
    removeFromBag ({ commit }, payload) {
      if (confirm('Você quer remover este produto do carrinho ?')) {
        commit('REMOVE_FROM_BAG', payload.product.id)
      }      
    },
    decreaseProduct ({ commit }, payload) {
      commit('DECREASE_PRODUCT', payload.product)
    },
    increaseProduct ({ commit }, payload) {
      commit('INCREASE_PRODUCT', payload.product.id)
    }
  },
  getters: {
    getProductsInBag(state) {
        return state.productsInBag
    },   
  } 
}

I'll also leave a part of the component code:

import globalMixin from '@/mixins/globalMixins'
import { mapState } from 'vuex'
import { mapGetters } from 'vuex'

export default {
  name: 'CartView',
  mixins: [globalMixin],
  computed: {
    ...mapState('products', ['productsInBag'])
  },
  methods: {
    ...mapGetters("products", ["getProductsInBag"]),
  }
}
<template>
  <div >
    <div  v-for="product in productsInBag" :key="product.id">
      <div >
        <p>{{ product.name }}</p>
      </div>
      <div >
        <button @click="() => $store.dispatch({type: 'products/decreaseProduct', product})">-</button>
          <span >{{ product.quantity }}</span>
        <button @click="() => $store.dispatch({type: 'products/increaseProduct', product})"> </button>
      </div>
      <div >
        <p>
          <span >{{ brazilianCurrency(product.price) }}</span> à vista ou {{ divideValue(product.price) }}
        </p>
      </div>
      <div >
        <p>
          <span >{{ brazilianCurrency(product.price * product.quantity) }}</span> à vista ou {{ divideValue(product.price * product.quantity) }}
        </p>
      </div>
    </div>
  </div>
</template>

In Vue Devtools states work perfectly. Look:

enter image description here

Would be great If you can help me. I've been looking for a solution for this for 6 hours.

CodePudding user response:

Vue. set is a tool that allows us to add a new property to an already reactive object and makes sure that this new property is ALSO reactive.

So, according to your problem, Vue.set will work well for you. Use it like this-

Vue.set(state.productsInBag, itemIndex, product)

Optional-

Also by looking at your fiddle's code, you can make a common function in your helper file to find the product's index like his-

export const findByIndex = (arr, matcher) => {
 return arr.findIndex(item => item.id === matcher)
}

And import this function in your js file like this-

import { findByIndex } from "YOUR_HELPER_FILE_PATH"

Now, the mutations can use like this-

DECREASE_PRODUCT(state, product) {     
  let itemIndex = findByIndex(state.productsInBag, product.id)
  if(itemIndex != -1) {
    product.quantity--
    Vue.set(state.productsInBag, itemIndex, product)
  }
},

INCREASE_PRODUCT(state, product) {    
  let itemIndex = findByIndex(state.productsInBag, product.id)
  if(itemIndex != -1) {
    product.quantity  
    Vue.set(state.productsInBag, itemIndex, product)
  }
}

A Little Tip-

Instead of making two mutation methods, a single mutation can be created which will accept the product_id and operation (increase or decrease) in an object, like this-

UPDATE_PRODUCT(state, payload) {
  // payload is an object which will have some data
  let itemIndex = findByIndex(state.productsInBag, payload.product_id)
  if(itemIndex != -1) {
    payload.operation == 'increase' ? product.quantity-- : product.quantity  ;
    Vue.set(state.productsInBag, itemIndex, product)
  }
}
  • Related