Victor
Victor

Reputation: 5353

VueJS does not rerender list even though array has changed & v-key is specified

I have two entities: categories and subcategories and two lists. When user selects a category I display subcategory list.

At first try it works fine, but when I change category I got old subcategory list.

Both categories and subcategories are in vuex store.

I tried to calculated subcategories next ways:

  1. Computed property
  2. When user selects a category I invoke a method, which filters subcategories by category_id and returns new list

Nothing worked for me. Here is an example of computed property:

subCategories() {
  return this.getClothingSubCategories.filter((subCategory) => {
    return subCategory.clothing_category_id === this.category.clothing_category_id
  })
},

Where this.getClothingSubCategories is a vuex getter.

What's weird is that both in vue plugin (in chrome developer tools) and console I got the list updated, but in html the list is old.

Here is how I display the list:

<VuePerfectScrollbar class="categories"
                     v-if="showSubCategories"
                     v-once>
  <ul>
    <li v-for="subCategory in subCategories"
        :key="subCategory.clothing_subcategory_id"
        @click="selectSubCategory(subCategory)">
      <div class="title">{{ subCategory.title }}</div>
      <div class="arrow">></div>
    </li>
  </ul>
</VuePerfectScrollbar>

So, the subCategories property relies on category object, which I set simply:

selectCategory(category) {
  this.category = category
},

When user selects a category.

I specified :key, tried different approaches but nothing worked, I always get the old list of subCategories.

What could be the reason?

update

Vuex getter:

export const getClothingSubCategories = (state) => {
  return state.clothingSubCategories
}

Component data:

data() {
    return {
      gender: 'female',
      category: null,
      subCategory: null,
      good: null,

      filters: {
        gender: 'female',
        clothing_subcategory_id: null
      }
    }
  },

Upvotes: 2

Views: 1269

Answers (1)

acdcjunior
acdcjunior

Reputation: 135802

Consider your declaration:

<VuePerfectScrollbar class="categories"
                     v-if="showSubCategories"
                     v-once>
  <ul>
    <li v-for="subCategory in subCategories"
        :key="subCategory.clothing_subcategory_id"
        @click="selectSubCategory(subCategory)">
      <div class="title">{{ subCategory.title }}</div>
      <div class="arrow">></div>
    </li>
  </ul>
</VuePerfectScrollbar>

The subCategories value, which is a computed property:

subCategories() {
  return this.getClothingSubCategories.filter((subCategory) => {
    return subCategory.clothing_category_id === this.category.clothing_category_id
  })
},

is supposed to be updated whenever category changes.

As you reported, it does. As it should.

Your problem, though is:

v-once

Details:

Render the element and component once only. On subsequent re-renders, the element/component and all its children will be treated as static content and skipped. This can be used to optimize update performance.

That is, as soon as Vue renders the subcategory collection the first time it "freezes" it. Basically, because of v-once it will never be updated again.

Solution: remove v-once.

I suggest you remove from other places in your code as well. Any element you want to be updated should not have v-once.

Upvotes: 1

Related Questions