使用 ChartJS 通过 Vue 获得 "Maximum call stack size exceeded"
Got "Maximum call stack size exceeded" with Vue using ChartJS
我想将数据从 Parent 传递给具有反应性的 GrandChild(即图表),所以我使用了道具。
This is the Parent
下面的 "kalkulator-data" 组件可以工作,它用于向 Parent 添加数据。
<template>
<div class="container">
<div class="row">
<kalkulator-data
:saldoAwal="saldoAwal"
:saldoTerpakai="saldoTerpakai"
:saldoAkhir="saldoAkhir"
:dataKategori="dataKategori"
:dataPengeluaran="dataPengeluaran"
@inputSaldo="saldoAwal = $event"
@inputPengeluaran="dataPengeluaran.push($event)">
</kalkulator-data>
<kalkulator-chart
:chartData="chartData"
:chartOptions="chartOptions">
</kalkulator-chart>
</div>
</div>
</template>
<script>
import Chart from './Bagian/Chart.vue';
import Data from './Bagian/Data.vue';
export default {
data(){
return {
saldoAwal : 0,
dataPengeluaran : [{ kategori : 'Abi', nominal : 12}, { kategori : 'Ilham', nominal : 13}],
dataKategori : [
'Makan dan Minum',
'Berbelanja',
'Perlengkapan Rumah',
'Transportasi',
'Kendaraan',
'Gaya Hidup dan Hiburan',
'Komunikasi',
'Pengeluaran dan Finansial',
'Investasi',
],
chartOptions : {responsive: true, maintainAspectRatio: false}
}
},
computed : {
saldoTerpakai(){
var saldoPakai = 0;
for(var data of this.dataPengeluaran){
saldoPakai += parseInt(data.nominal);
}
return saldoPakai;
},
saldoAkhir(){
return this.saldoAwal - this.saldoTerpakai;
},
getRandomColor(){
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
},
chartLabels(){
var chartLabels = [];
for (var data of this.dataPengeluaran ){
chartLabels.push(data.kategori);
// backgroundColor.push(this.getRandomColor);
};
return chartLabels;
},
chartId(){
var chartData = [];
for (var data of this.dataPengeluaran ){
chartData.push(parseInt(data.nominal));
// backgroundColor.push(this.getRandomColor);
};
return chartData;
},
chartData(){
return {
labels: this.chartLabels,
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
data: this.chartId
}
]
}
}
},
methods : {
},
components : {
'kalkulator-data' : Data,
'kalkulator-chart' : Chart
},
}
</script>
This is the Child
<template>
<div class="col-sm-6">
<div class="row">
<h1 class="text-center">Struktur Pengeluaran</h1>
<chart-comp
:chartData="chartData"
:chartOptions="chartOptions">
</chart-comp>
</div>
</div>
</template>
<script>
import chartComp from './Chart-Data.js'
export default{
props : ['chartData', 'chartOptions'],
components : {
'chart-comp' : chartComp
}
}
</script>
And this the GrandChild which is Chart
import {Bar} from 'vue-chartjs'
export default Bar.extend({
props : ['chartData', 'chartOptions'],
computed : {
renderChart(){
this.renderChart(this.chartData, this.chartOptions);
}
},
mounted () {
this.renderChart;
}
})
我正在使用计算来保持添加数据时的反应性,但它在控制台中说:
app.js:5366 [Vue warn]: Error in mounted hook: "RangeError: Maximum call stack size exceeded"
found in
---> <ChartComp>
<KalkulatorChart> at C:\xampp\htdocs\SemuaOkee-Laravel\resources\assets\js\components\Bagian\Chart.vue
<Kalkulator> at C:\xampp\htdocs\SemuaOkee-Laravel\resources\assets\js\components\Kalkulator.vue
<Root>
warn @ app.js:5366
handleError @ app.js:5451
callHook @ app.js:7490
insert @ app.js:8315
invokeInsertHook @ app.js:10143
patch @ app.js:10308
Vue._update @ app.js:7248
updateComponent @ app.js:7371
get @ app.js:7710
Watcher @ app.js:7693
mountComponent @ app.js:7375
Vue.$mount @ app.js:12503
Vue.$mount @ app.js:14602
Vue._init @ app.js:8942
Vue @ app.js:9027
(anonymous) @ app.js:29926
__webpack_require__ @ app.js:20
(anonymous) @ app.js:29888
__webpack_require__ @ app.js:20
(anonymous) @ app.js:63
(anonymous) @ app.js:66
app.js:5455 RangeError: Maximum call stack size exceeded
at Watcher.evaluate (app.js:7809)
at VueComponent.computedGetter [as renderChart] (app.js:8064)
at VueComponent.renderChart (app.js:61047)
at Watcher.get (app.js:7710)
at Watcher.evaluate (app.js:7810)
at VueComponent.computedGetter [as renderChart] (app.js:8064)
at VueComponent.renderChart (app.js:61047)
at Watcher.get (app.js:7710)
at Watcher.evaluate (app.js:7810)
at VueComponent.computedGetter [as renderChart] (app.js:8064)
当我还没有添加数据时,它工作得很好(这就是为什么我在 Parent 中硬编码两个对象以在开始时测试我的图表),但是当我添加了一个数据,它有一个错误。
换句话说,它适用于静态数据,但不适用于动态数据。
在您的孙子组件中,您定义了一个计算 属性 renderChart
,其中 returns this.renderChart
。这就是导致最大调用堆栈大小错误的原因。
您应该只调用 mounted
挂钩中的 renderChart
方法:
import { Bar } from 'vue-chartjs'
export default Bar.extend({
props: ['chartData', 'chartOptions'],
mounted() {
this.renderChart(this.chartData, this.chartOptions);
}
})
如果您需要图表数据是反应式的,vue-chartjs 提供了一种公认的愚蠢方法来指定使用 mixin:
import { Bar, mixins } from 'vue-chartjs'
export default Bar.extend({
props: ['chartData', 'chartOptions'],
mixins: [mixins.reactiveProp],
mounted() {
this.renderChart(this.chartData, this.chartOptions);
}
})
Here's the vue-chartjs documentation on using reactive data.
我在 vue.js 渲染组件时遇到同样的错误,你必须在重新填充值之前销毁图表,你可以像我下面那样做:
<script>
import Chart from 'chart.js';
export default {
name: 'card',
props: {
chartData: {
type: Object,
required: true,
},
},
mounted() {
this.createChart('planet-chart', this.chartData);
},
data() {
return {
myChart: null
}
},
methods:{
createChart(chartId, chartData) {
const ctx = document.getElementById(chartId);
this.myChart = new Chart(ctx, {
type: chartData.type,
data: chartData.data,
options: chartData.options,
});
}
},
beforeDestroy() {
if(this.myChart) {
this.myChart.destroy();
}
}
};
</script>
我想将数据从 Parent 传递给具有反应性的 GrandChild(即图表),所以我使用了道具。
This is the Parent
下面的 "kalkulator-data" 组件可以工作,它用于向 Parent 添加数据。
<template>
<div class="container">
<div class="row">
<kalkulator-data
:saldoAwal="saldoAwal"
:saldoTerpakai="saldoTerpakai"
:saldoAkhir="saldoAkhir"
:dataKategori="dataKategori"
:dataPengeluaran="dataPengeluaran"
@inputSaldo="saldoAwal = $event"
@inputPengeluaran="dataPengeluaran.push($event)">
</kalkulator-data>
<kalkulator-chart
:chartData="chartData"
:chartOptions="chartOptions">
</kalkulator-chart>
</div>
</div>
</template>
<script>
import Chart from './Bagian/Chart.vue';
import Data from './Bagian/Data.vue';
export default {
data(){
return {
saldoAwal : 0,
dataPengeluaran : [{ kategori : 'Abi', nominal : 12}, { kategori : 'Ilham', nominal : 13}],
dataKategori : [
'Makan dan Minum',
'Berbelanja',
'Perlengkapan Rumah',
'Transportasi',
'Kendaraan',
'Gaya Hidup dan Hiburan',
'Komunikasi',
'Pengeluaran dan Finansial',
'Investasi',
],
chartOptions : {responsive: true, maintainAspectRatio: false}
}
},
computed : {
saldoTerpakai(){
var saldoPakai = 0;
for(var data of this.dataPengeluaran){
saldoPakai += parseInt(data.nominal);
}
return saldoPakai;
},
saldoAkhir(){
return this.saldoAwal - this.saldoTerpakai;
},
getRandomColor(){
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
},
chartLabels(){
var chartLabels = [];
for (var data of this.dataPengeluaran ){
chartLabels.push(data.kategori);
// backgroundColor.push(this.getRandomColor);
};
return chartLabels;
},
chartId(){
var chartData = [];
for (var data of this.dataPengeluaran ){
chartData.push(parseInt(data.nominal));
// backgroundColor.push(this.getRandomColor);
};
return chartData;
},
chartData(){
return {
labels: this.chartLabels,
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
data: this.chartId
}
]
}
}
},
methods : {
},
components : {
'kalkulator-data' : Data,
'kalkulator-chart' : Chart
},
}
</script>
This is the Child
<template>
<div class="col-sm-6">
<div class="row">
<h1 class="text-center">Struktur Pengeluaran</h1>
<chart-comp
:chartData="chartData"
:chartOptions="chartOptions">
</chart-comp>
</div>
</div>
</template>
<script>
import chartComp from './Chart-Data.js'
export default{
props : ['chartData', 'chartOptions'],
components : {
'chart-comp' : chartComp
}
}
</script>
And this the GrandChild which is Chart
import {Bar} from 'vue-chartjs'
export default Bar.extend({
props : ['chartData', 'chartOptions'],
computed : {
renderChart(){
this.renderChart(this.chartData, this.chartOptions);
}
},
mounted () {
this.renderChart;
}
})
我正在使用计算来保持添加数据时的反应性,但它在控制台中说:
app.js:5366 [Vue warn]: Error in mounted hook: "RangeError: Maximum call stack size exceeded"
found in
---> <ChartComp>
<KalkulatorChart> at C:\xampp\htdocs\SemuaOkee-Laravel\resources\assets\js\components\Bagian\Chart.vue
<Kalkulator> at C:\xampp\htdocs\SemuaOkee-Laravel\resources\assets\js\components\Kalkulator.vue
<Root>
warn @ app.js:5366
handleError @ app.js:5451
callHook @ app.js:7490
insert @ app.js:8315
invokeInsertHook @ app.js:10143
patch @ app.js:10308
Vue._update @ app.js:7248
updateComponent @ app.js:7371
get @ app.js:7710
Watcher @ app.js:7693
mountComponent @ app.js:7375
Vue.$mount @ app.js:12503
Vue.$mount @ app.js:14602
Vue._init @ app.js:8942
Vue @ app.js:9027
(anonymous) @ app.js:29926
__webpack_require__ @ app.js:20
(anonymous) @ app.js:29888
__webpack_require__ @ app.js:20
(anonymous) @ app.js:63
(anonymous) @ app.js:66
app.js:5455 RangeError: Maximum call stack size exceeded
at Watcher.evaluate (app.js:7809)
at VueComponent.computedGetter [as renderChart] (app.js:8064)
at VueComponent.renderChart (app.js:61047)
at Watcher.get (app.js:7710)
at Watcher.evaluate (app.js:7810)
at VueComponent.computedGetter [as renderChart] (app.js:8064)
at VueComponent.renderChart (app.js:61047)
at Watcher.get (app.js:7710)
at Watcher.evaluate (app.js:7810)
at VueComponent.computedGetter [as renderChart] (app.js:8064)
当我还没有添加数据时,它工作得很好(这就是为什么我在 Parent 中硬编码两个对象以在开始时测试我的图表),但是当我添加了一个数据,它有一个错误。
换句话说,它适用于静态数据,但不适用于动态数据。
在您的孙子组件中,您定义了一个计算 属性 renderChart
,其中 returns this.renderChart
。这就是导致最大调用堆栈大小错误的原因。
您应该只调用 mounted
挂钩中的 renderChart
方法:
import { Bar } from 'vue-chartjs'
export default Bar.extend({
props: ['chartData', 'chartOptions'],
mounted() {
this.renderChart(this.chartData, this.chartOptions);
}
})
如果您需要图表数据是反应式的,vue-chartjs 提供了一种公认的愚蠢方法来指定使用 mixin:
import { Bar, mixins } from 'vue-chartjs'
export default Bar.extend({
props: ['chartData', 'chartOptions'],
mixins: [mixins.reactiveProp],
mounted() {
this.renderChart(this.chartData, this.chartOptions);
}
})
Here's the vue-chartjs documentation on using reactive data.
我在 vue.js 渲染组件时遇到同样的错误,你必须在重新填充值之前销毁图表,你可以像我下面那样做:
<script>
import Chart from 'chart.js';
export default {
name: 'card',
props: {
chartData: {
type: Object,
required: true,
},
},
mounted() {
this.createChart('planet-chart', this.chartData);
},
data() {
return {
myChart: null
}
},
methods:{
createChart(chartId, chartData) {
const ctx = document.getElementById(chartId);
this.myChart = new Chart(ctx, {
type: chartData.type,
data: chartData.data,
options: chartData.options,
});
}
},
beforeDestroy() {
if(this.myChart) {
this.myChart.destroy();
}
}
};
</script>