Reputation: 1000
I know this has been answered before, but after looking at "You may have an infinite update loop in a component render function" warning in Vue component I found the solution did not work.
Can someone help me figure out what is going on here?
<template>
<div>
<template v-for="listing in sortedListings">
<listing
:key="listing.uuid"
:listing="listing"
:highlight-color="listing.highlight ? getHighlightColor() : null"
/>
</template>
</div>
</template>
<script>
import Listing from '@/components/Listing'
export default {
components: {
Listing,
},
data: function () {
return {
highlightColors: this.getHighlightColors(),
listings: [
{
uuid: '658f325f-33c8-455b-98f6-27eb4eaa16a0',
title: 'Cursus Nullam Amet Tortor',
location: 'Remote',
url: 'http://example.net/birds',
hours_week: 20,
tags: ['django', 'python', 'flask'],
logo: 'https://logo.clearbit.com/apple.com',
company_name: 'Apple',
show_logo: 1,
highlight: 0,
stick_top: 0,
},
{
uuid: '658f325f-33c8-455b-98f6-27eb4eaa16a1',
title: 'Donec id elit non mi porta gravida at eget metus',
location: 'Remote',
url: 'http://example.net/birds',
hours_week: 20,
tags: ['django', 'python', 'flask', 'full-stack', 'contract'],
logo: 'https://logo.clearbit.com/apple.com',
company_name: 'Mapple',
show_logo: 0,
highlight: 0,
stick_top: 0,
},
{
uuid: '658f325f-33c8-455b-98f6-27eb4eaa16a2',
title:
'Donec ullamcorper nulla non metus auctor fringilla ullamcorper dapibus',
location: 'Remote / USA',
url: 'http://example.net/birds',
hours_week: 20,
tags: ['django', 'python', 'flask', 'full-stack', 'vue.js'],
logo: 'https://logo.clearbit.com/apple.com',
company_name: 'Fapple',
show_logo: 1,
highlight: 0,
stick_top: 1,
},
{
uuid: '658f325f-33c8-455b-98f6-27eb4eaa16a3',
title: 'Tristique Euismod Venenatis Porta',
location: 'San Francisco, CA, USA',
url: 'http://example.net/birds',
hours_week: 20,
tags: ['django', 'python', 'flask', 'full-stack', 'vue.js'],
logo: 'https://logo.clearbit.com/apple.com',
company_name: 'Lapple',
show_logo: 1,
highlight: 1,
stick_top: 0,
},
{
uuid: '658f325f-33c8-455b-98f6-27eb4eaa16a4',
title: 'Tristique Euismod Venenatis',
location: 'San Francisco, CA, USA',
url: 'http://example.net/birds',
hours_week: 20,
tags: ['django', 'python', 'flask', 'full-stack', 'vue.js'],
logo: 'https://logo.clearbit.com/apple.com',
company_name: 'Dapple',
show_logo: 1,
highlight: 1,
stick_top: 1,
},
],
}
},
computed: {
sortedListings: function () {
return [...this.listings].sort(function (a, b) {
return b.stick_top - a.stick_top
})
},
},
methods: {
getListings: async function () {},
getHighlightColors: function () {
return this.shuffleArray([
'#E3F2FD',
'#E8EAF6',
'#FFEBEE',
'#E0F2F1',
'#E8F5E9',
'#FFF3E0',
'#FFFDE7',
])
},
getHighlightColor: function () {
if (this.highlightColors.length === 0) {
this.highlightColors = this.getHighlightColors()
}
return this.highlightColors.shift()
},
},
mounted: function () {
this.getListings()
},
}
</script>
Within the computed property sortedListings
I am already doing [...this.listings]
Upvotes: 1
Views: 334
Reputation: 63089
getHighlightColor()
is causing the infinite loop.
This is a classic illustration of why it can be bad (not always) to bind to a method in the template. If your method changes a model, Vue has to rerender the component. Which then triggers the method and changes the model again, which then causes a rerender of the component, and so on.
This demo will produce the same result but not if you use the computed in the template instead:
new Vue({
el: "#app",
data() {
return {
arr: [1,2,3,4,5]
}
},
methods: {
change: function () {
return this.arr.shift();
},
},
computed: {
test() {
return this.arr.shift();
}
}
});
<div id="app">
<div>
{{ change() }}
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
Upvotes: 2
Reputation: 1
the spread operator doesn't deep clone the array and the sort method modify the original property which is used in computed that generate an infinite loop, so add a method to clone the object deeply like this one :
...
computed: {
sortedListings: function () {
return this.deepCopy(this.listings).sort(function (a, b) {
return b.stick_top - a.stick_top
})
},
},
methods: {
deepCopy(src) {
let target = Array.isArray(src) ? [] : {};
for (let prop in src) {
let value = src[prop];
if(value && typeof value === 'object') {
target[prop] = deepCopy(value);
} else {
target[prop] = value;
}
}
return target;
}
,
getListings: async function () {},
...
Upvotes: 2