简体   繁体   中英

Vue component doesn't reload with getter data (not reactive)

I have this ecommerce mock app in Vue and Vuex. This page shows a list of phones and there is a filter which filters phones based on the phone brands through checkboxes.

The problem is the page doesn't refresh straight away after I click the checkbox to filter. If I click another page and click back to the original page, then the page gets filtered.

在此处输入图像描述

The is my source code. Some code is removed for brevity.

Product.vue

 import { mapActions } from "vuex"; import BrandFilter from "../components/BrandFilter"; export default { data() { return { products: this.$store.getters.filterProducts }; }, components: { BrandFilter } };
 <template> <div class="container"> <div class="row"> <div class="col-lg-3"><BrandFilter></BrandFilter></div> <div class="col-lg-9"> <div class="row"> <div v-for="product in products":key="product.id"> <h4 class="card-title product__title"> {{ product.title }} </h4> </div> </div> </div> </div> </div> </template>

BrandFilter.vue

 export default { name: "BrandFilter", data() { return { brands: this.$store.state.brands }; }, methods: { onChangeSelectBox(e) { debugger; const name = e.target.name; const value = e.target.checked; if (value) { this.$store.commit("addBrandToFilter", name); } else { this.$store.commit("removeBrandFromFilter", name); } } } };
 <template> <div class="card mb-3"> <div class="card-header"> <h3>Brands</h3> </div> <ul class="list-group flex-row flex-wrap"> <li class="list-group-item flex-50" v-for="brand in brands":key="brand"> <label class="custom-checkbox text-capitalize"> {{ brand }} <input type="checkbox":name="brand" class="custom-checkbox__input" @input="onChangeSelectBox($event)" /> <span class="custom-checkbox__span"></span> </label> </li> </ul> </div> </template>

store/index.js

 import Vue from "vue"; import Vuex from "vuex"; import { phones } from "../data/phones"; import { brands } from "../data/brands"; import { brandFilter } from "../filters/brandFilter"; Vue.use(Vuex); export default new Vuex.Store({ strict: true, state: { products: phones, brands: brands, cart: [], brandFilter: "" }, getters: { filterProducts(state) { debugger; const brands = state.brandFilter; const filterByBrandArr = brandFilter(state.products, brands); return filterByBrandArr; } }, mutations: { addBrandToFilter: (state, brand) => { debugger; if (state.brandFilter.includes(brand)) return void 0; state.brandFilter += brand; }, removeBrandFromFilter: (state, brand) => { debugger; const reg = new RegExp(brand, "gi"); state.brandFilter = state.brandFilter.replace(reg, ""); } } });

When you set a data item to a getter in Product.vue , it gets assigned only once. If the getter changes, the data doesn't change with it:

data() {
  return {
    products: this.$store.getters.filterProducts  // ❌ Incorrect
  }
}

Use a computed instead with mapGetters to keep the component data synced with the Vuex data:

import { mapGetters } from 'vuex';
computed: {
  ...mapGetters(['filterProducts'])  // ✅ Correct
}

Change your template to use that computed:

<div v-for="product in filterProducts" :key="product.id">            
   <h4 class="card-title product__title">
      {{ product.title }}
   </h4>                            
</div>

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