Ph33ly
Ph33ly

Reputation: 693

Infinite loop when using computed property with Vue Chart js

I'm trying to update my chart every 5 seconds with new data from an API call. My chart is updating but is rendering each point hundreds of times each. I checked the logs and it shows that there's an infinite loop being caused and I'm not sure how to resolve this. Below is my current code:

Note: 'graphData' prop is an Array I'm passing from Parent that is data from API call that I want added to chart

ChildComponent.vue

<template>
<div class="graphCard">
    <Linechart :chartData="dataCollection" :options="options" />
</div>
</template>


<script>
import Linechart from '@/utils/Linechart.js'

export default {
components: {
    Linechart
},
props: ['graphData'],
data() {
    return {
        collection: []
    }
},  
computed: {       
    dataCollection() { 
        this.collection.push(this.graphData[0])
        return { 
            datasets: [
                    {
                    label: 'chart',
                    backgroundColor: 'indigo',
                    borderColor: 'indigo',
                    fill:false,
                    showLine: true,
                    data: this.collection
                    }]
        }    
},
options() {
        return {
            id: 'Cumulative',
            legend: {
                display: false
            },
            scales: {
                xAxes: [{
                    type: 'time',
                    distribution: 'series',
                    time: {
                        displayFormats: {
                            millisecond: 'mm:ss:SS',
                            quarter: 'MMM YYYY'
                        } 
                    }
                }],
                yAxes: [{
                    ticks: {
                        //beginAtZero: true
                    }
                }]
            }
        }
    }

LineChart.js

import { Scatter, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins

export default {
    extends: Scatter,
    mixins: [reactiveProp],
    props: ['chartData', 'options'],
    mounted () {
        this.renderChart(this.chartData, this.options)
    }
}

In an alternative approach I also tried to set up dataCollection and options as 'data' instead of 'computed,' with a watcher on the graphData prop, but the chart did not update and ran into an issue 'Uncaught TypeError: Cannot read property 'skip' of undefined'

Upvotes: 1

Views: 1991

Answers (2)

Ph33ly
Ph33ly

Reputation: 693

@BTL got me on the right track with the approach but some issues still prevented the graph from updating correctly. It seems the chartData can't properly update if new data is pushed directly onto the dataset. What worked for me:

watch: {
    graphData (newData) {
        currentDataList.push(newData[0])
        this.dataCollection = { 
            datasets: [{
                label: 'label',
                backgroundColor:'red',
                borderColor: 'red',
                fill:false,
                showLine: true,
                lineTension: 0,
                data: currentDataList
            }]
        }
    }
}

Upvotes: 0

BTL
BTL

Reputation: 4656

Normally a computed is better than a watcher but I'm not sure I can debug this infinite loop without more context. So here is the data + watch alternative who should work.

The code :

<template>
<div class="graphCard">
    <Linechart :chartData="dataCollection" :options="options" v-if="dataCollection.datasets[0].data.length"/>
</div>
</template>

<script>
import Linechart from '@/utils/Linechart.js'

export default {
    components: {
        Linechart
    },
    props: ['graphData'],
    data() {
        return {
            dataCollection: {
                datasets: [{
                    label: 'chart',
                    backgroundColor: 'indigo',
                    borderColor: 'indigo',
                    fill:false,
                    showLine: true,
                    data: []
                    }]
            },
            options: {
                id: 'Cumulative',
                legend: {
                    display: false
                },
                scales: {
                    xAxes: [{
                        type: 'time',
                        distribution: 'series',
                        time: {
                            displayFormats: {
                                millisecond: 'mm:ss:SS',
                                quarter: 'MMM YYYY'
                            }
                        }
                    }],
                    yAxes: [{
                        ticks: {
                            //beginAtZero: true
                        }
                    }]
                }
            }
        }
    },
    watch: {
      graphData (newData) {
        this.dataCollection.datasets[0].data.push(newData[0])
      }
    }
}

Upvotes: 1

Related Questions