Vue does not update items in v-for from Vuex with dynamic component

Arsync

We have a dynamic component for tab body, which defined as

<component :is="currentTab.itemType" :itemId="currentTab.itemId"></component>

Template has a span, which reflects itemId - it changes every time when the currentTab changed in tabs host component.

Each component of tab.itemType has Vuex module, belongs to it specific type.

For example, there is store module product with described state:

{
  products: { [itemId: string]: IProduct }
}

When component created or itemId changed, it tries to run load action and put loaded product to products of vuex state.

So, there is Vue computed property, looks like

@State(productNamespace)
state: IProductState;

get currentProduct() {

  return this.state.products[this.itemId];
}

or even

@Getter(GetterNames.GET_PRODUCT_BY_ID, bindingOptions)
getProductById: (itemId: string) => IProduct;

get currentProduct() {

  return this.getProductById(this.itemId);
}

Each product has attributes list, wich iterated by v-for with :key.

<v-list :key="itemId"><!-- itemId has no effect there -->
  <v-list-item v-for="attribute in currentProduct.attributes" :key="attribute.id">
    ...
  </v-list-item>
</v-list>

The problem is: when we change itemId, the attributes list displays all attributes from last added product and does not refresh it when switching to previous "tabs" with another itemId but the same itemType.

I've tried to set :key of parent div as itemId but with no effect. When I set :key to <component>, vuex state becomes broken.

Vue version is 2.6.10

UPDATE:

It does not work with simple property of product too:

{{ currentProduct.name }}

Summary:

There is the itemId property in. And computed property wich depends on it. So computed property does not reflect changes when itemId prop changed while Vuex collection does not changed.

Confirmed:

Computed property renews only when state.products collection changed. I've emulate this by run createProduct action for each tab switching. Collection in vuex state accepts unwatched product stub and reflect changes to legal currentProduct with given itemId

UPDATE 2: component with watcher. Still no way...

@Component
export default class Product extends Vue {

  @Prop({ type: Object, required: true })
  readonly tabItem: ITabItem;

  @State(productNamespace)
  state: IProductState;

  itemId: string;

  created() {

    //...
    this.initCurrentProduct();
  }

  // No changes until state.products was changed.   
  get currentProduct(): IProduct | {} {

    if (!this.state) return {};     
    return this.state.products[this.itemId];
  }

  @Watch('tabItem')
  onTabItemChanged()
  {
    DEBUG && console.log('Tab changed: keep moving!');
    this.initCurrentProduct();
  }

  private async initCurrentProduct() {

    const { isNew, itemId } = this.tabItem;

    if (itemId === this.itemId)
      return;

    DEBUG && console.log('ItemId changed.');
    this.itemId = itemId;

    // ...
  }

  // ...
}

Shitiz Garg

Okay so the property you're passing to the dynamic component is currentTab.itemId which means itemId is actually an element in the currentTab object not the root Vue data object?

Vue does not track nested objects by default, it will only trigger redraw when the entire object is changed (for example if you do something like currentTab = {...}). You can either:

  1. Use a watcher on currentTab with deep: true attribute: https://vuejs.org/v2/api/#watch, and then trigger redraw with this.$forceUpdate whenever it is called.

  2. Move itemId to the root of data and just update it from there

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

dynamic vue component access to vuex

Vuex store does not update component collection when pushing from mutation

Vue3: problems with v-model, it does not update the component

dynamic v-for rendering from http get results to vue component

My component does not react to change Vue with Vuex

Component: Update `Items` from `TComboBox`

vue v-for does not update when vuex getter returns a new array

Pass data from Vue Component to Vuex store

Does Vue automatically remove all vue/vuex watchers on component destroy?

Trigger/update data change from child component to parent component in Quasar/Vue incase of child component has list of items

Vuex: How to update component data or call component methods from Store

Vue: Update Component data from Vue instance

Nativescript Vue ListPicker does not update it's items

vue.js - dynamically generated component in v-for does not update bound property correctly

mapstate to dynamic state objects of vuex store from the component

Vue3, Vuex does not update DOM element

How to get vuex state from a javascript file (instead of a vue component)

How to propagate an error from vuex action to vue component?

How to pass data from vuex store through module to vue component?

Vue - How to access component's property from Vuex

Pass id from Vue router param to component's Vuex dispatch

Vue3: Get updated state from Vuex into component

Vue v-on:click does not work on component

V-snackbar does not display when I update the Vuex state

Change value fo v-model from other component with vuex

Update parent model from child component Vue

Update child component from parent in Vue js

Vue 3 custom checkbox component with v-model and array of items

Vue JS- Cannot update html table with data from Vuex