2
votes

I have array with components data and try render it with v-for

<div :style="style" class="editor-component" v-for="(component, index) in components">
    <Component
       :is="component.name"
       v-bind="component.options"
       :key="createKey(component, index)"
       :style="component.style ? component.style : {}"
    />
</div>

So problem:

When component.options has array prop with 1 element, like

tabs: [{tab}]

it's works nice, but when tabs have 2 and more tab, like this

tabs: [{tab},{tab}]

Component don't watch changes in second tab.

So, i solved it with dinamical key

createKey(component, index) {
   return JSON.stringify(component) + index
}

but it makes component re-render after each change, and reset component state to default.

UPD: I've found same problem Reactive Nested V-For's using Vue/Vuex but it hasn't answer :(

3
What did you use as key before? For reactivity it is also important to see, how you change the data. Can you please post that code? - bodo
I used as key index. I change data with mutation @Mutation setComponent(component: PageComponent) { let index = this.components.findIndex(i => (i.name === component.name) && i.edit); Vue.set(this.components, index, component); } - Андрей Луговской
If components is an array, try adding the data with components.push. - bodo
I would add the key, or a new key to the "editor-component" Div so when that div changes with both of the components inside it will rerender, Also checkout the final section of this article about force-re-rednering: michaelnthiessen.com/force-re-render - Sweet Chilly Philly

3 Answers

2
votes

Happy to help

I would add the key, or a new key to the "editor-component" Div so when that div changes with both of the components inside it will rerender, Also checkout the final section of this article about force-re-rednering: https://michaelnthiessen.com/force-re-render

To fix your issue with the tabs being reset each time: have a read of this article: Vuex state on page refresh and multiple tabs

I think you need to look at vuex or something similar for persisted state.

1
votes

Thanks @Sweet Chilly Philly, i've almost solved problem

        createKey(component, index) {
            let count = this.countOptionsLength(component.options);
            console.log(component.name, count);
            return `component_${index}_length_${count}`;
        }

        countOptionsLength(options) {
            let cnt = 0;

            for(let key in options) {
                if(options.hasOwnProperty(key)) {
                    let option = options[key];
                    if(Array.isArray(option)) {
                        cnt += option.length;
                    }
                    if(option && (Array.isArray(option) || isObj(option))) {
                        cnt += this.countOptionsLength(option)
                    }
                }
            }
            return cnt;
        }
        ...
<div :style="style" class="editor-component" v-for="(component, index) in components">
         <Component
                        :is="component.name"
                        v-bind="component.options"
                        :key="createKey(component, index)"
                        :style="component.style ? component.style : {}"
                />
</div>

I count length of arrays in options object, and generate key, and it's re-render component only if elelement add to array. But problem with b-tab(bootstrap-vue) still exists http://recordit.co/dpASWfvoaB

0
votes
<div :style="style" class="editor-component" v-for="(component, index) in components">
<Component
   :is="component.name"
   v-bind="component.options"
   :key="component.name"
   :style="component.style ? component.style : {}"
/>

I think you can just use the component name as a key. Because component name should be unique