简体   繁体   中英

Component inside v-for, Infinite update loop in a component render function

I am using a tabs component to display some information, each tab in the array is set in the data by getting all the child elements using this.tabs = this.$children . When displaying the name of each child tab using {{tab.name}} it works fine however when i add an svg component with the name set to tab.name so each icon is different based on this name it loops infinitely and I get the error

'You may have an infinite update loop in a component render function'.

I am relatively new to vue, I think that the fact that I am mutating the tabs array in data is causing the render function to fire over and over but I am not 100% sure.

If anyone can help me here it would be greatly appreciated as I have been trying to make this work for hours now!

Thanks in advance

I have tried removing the svg component and it works without an infinite loop.

Tabs component

<template>
    <div> 
        <section class="what-we-do u-bg--navy">
            <ul class="o-layout o-layout--tiny o-layout--center">
                <li v-for="tab in tabs" class="o-layout__item u-1/5@tablet u-text--center">
                    <div @click="selectTab(tab)" class="icon" v-bind:class="{'icon--active': tab.isActive }">
                        <h3 class="u-margin-bottom-none u-margin-top-tiny">{{tab.name}}</h3>
                        <svgicon
                            :name="tab.name"
                            width="200"
                            height="200"
                            color="currentColor"
                        ></svgicon>
                    </div>
                </li>
            </ul>
        </section>
        <section class="u-bg--yellow u-padding-vertical-large">
            <div class="o-wrapper">
                <div class="o-layout o-layout--center">
                    <slot></slot>
                </div>
            </div>
        </section>
    </div>
</template>
<script>
    import '../svgicons';

    export default {
        name: "Tabs",
        data() {
            return {
                tabs: []
            };
        },
        created() {
            this.tabs = this.$children;
        },
        methods: {
            selectTab(selectedTab) {
                this.tabs.forEach(tab => {
                    tab.isActive = (tab.name == selectedTab.name);
                });
            }
        }
    }
</script>

I would just like to have each svg in the loop get pulled in only once.

the vue-svgicon npm module creates components that look like this ...

/* eslint-disable */
var icon = require('vue-svgicon')
icon.register({
  'discover': {
    width: 16,
    height: 16,
    viewBox: '0 0 20 20',
    data: '<path pid="0" d="M10 3.7c-2.5 0-4.5 2-4.5 4.5 0 3 4.1 7.9 4.3 8.1 0 .1.1.1.2.1h0c.1 0 .1 0 .2-.1.2-.2 4.3-5 4.3-8.1 0-2.5-2-4.5-4.5-4.5zm0 12c-.8-1-4-5.1-4-7.5 0-2.2 1.8-4 4-4s4 1.8 4 4c0 0 0 0 0 0 0 2.5-3.2 6.5-4 7.5h0zm0-9.6C9 6.1 8.1 7 8.1 8s.9 2 1.9 2c1 0 1.9-.9 1.9-1.9 0-1.1-.9-2-1.9-2zm0 3.3c-.8 0-1.4-.6-1.4-1.4s.6-1.3 1.4-1.3c.8 0 1.4.6 1.4 1.4 0 .7-.6 1.3-1.4 1.3z" _fill="none" _stroke="#328cc1" stroke-width=".684"/>'
  }
})

The Tab component

<template>
    <transition
            name="custom-classes-transition"
            enter-active-class="animated fadeIn">

        <div class="o-layout__item u-3/4@tablet" v-show="isActive">
            <slot></slot>
        </div>
    </transition>
</template>
<script>
    export default {
        props: {
            name: {
                required: true
            },
            selected: {
                default: false
            }
        },
        data() {
            return {
                isActive: false
            };
        },
        computed: {
            href() {
                return '#' + this.name.toLowerCase().replace(/ /g, '-');
            }
        },
        mounted() {
            this.isActive = this.selected;
        }
    }
</script>

And it is being used in another component like this here...

<tabs>
    <tab name="events" :selected="true">
        <h1>Find out whats on</h1>

    </tab>
    <tab name="offers">
        <h1>Bringing you the best offers</h1>

    </tab>
    <tab name="inspire">
        <h1>Read inspiring articles</h1>

    </tab>
    <tab name="discover">
        <h1>Find places to go</h1>

    </tab>
    <tab name="savings">
        <h1>Savings</h1>
    </tab>
</tabs>

Try giving the name like so

:name="`${tab.name}`"

Cause what I understand is that you only wish to pass a string value to the component.

Also, try adding a type to your name prop to know if the data passed is of the correct type.

   props: {
        name: {
            type: String
            required: true
        },
        ...
    }

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