开发者问题收集

使用带有 Fetch 的 Props 向 Chartjs 添加数据时出现“最大调用堆栈大小”错误(Vue/Chartjs)

2021-08-03
906

我正在尝试使用一种方法从 json 文件中获取数据并将其添加到我的 chart.js 图表中。我一直收到“超出最大调用堆栈大小”的消息,这具体是由 this.chartData.push(el.value); 行引起的,我尝试过更改命名,但没有成功,也尝试过使用 this.$data.chartData

我正在使用 vue3、chart.js v3 和 j-t-mcc/vue3-chartjs

这里是 codesandbox.io 的代码,其中包含错误。

Child (chart) component

<template>
  <div class="card card-body bg-dark">
    <div class="col" id="chart">
      <vue3-chart-js
        ref="chartRef"
        :id="sampleChart.id"
        :type="sampleChart.type"
        :data="sampleChart.data"
        :options="sampleChart.options"
      ></vue3-chart-js>
    </div>
  </div>
</template>

<script>
import { ref } from 'vue'
import Vue3ChartJs from "@j-t-mcc/vue3-chartjs"
import 'chartjs-adapter-date-fns';

var chartOptions = {
  maintainAspectRatio: true,
  responsive: true,
  animation: {
    duration: 500
  },
  plugins: {
    legend: {
      display: false,
    },
    tooltip: {
      yAlign: "bottom",
    },
  },
  interaction: {
    mode: "index",
    intersect: false,
    axis: "x",
  },
  scales: {
    x: {
      type: "time",
      time: {
        unit: "minute"
      }
    },
    y: {
      beginAtZero: true,
    },
  },
  elements: {
    point: {
      pointRadius: 5.0,
    },
  },
  layout: {
    padding: {
      top: 20,
      left: 10,
      right: 10,
      bottom: 10,
    },
  },
}

export default {
  name: "Chart",
  components: {
    Vue3ChartJs,
  },
  props: {
    chartData: Array,
    chartLabels: Array
  },
  setup(props) {
    const chartRef = ref(null)
    console.log("area chart data", props.chartData)

    const chartDetails = {
      labels: props.chartLabels,
      fill: true,
      datasets: [
        {
          label: "",
          data: props.chartData,
          borderColor: "rgb(24, 144, 255)",
          tension: 0.1,
          fill: true,
        },
      ],
    }
    const sampleChart = {
      id: "line",
      type: "line",
      data: chartDetails,
      options: chartOptions,
    }

    return {
      sampleChart,
      chartRef
    }
  },
  watch: {
    chartLabels: {
      deep: true,
      handler() {
        this.chartRef.update(250)
      }
    }
  },
}
</script>

<style>
#chart {
  position: relative;
  margin: auto;
  height: 100%;
  width: 100%;
}
</style>

Parent component

<template>
  <div>
    <div class="container-fluid">
      <SampleChart :chart-data="chartData" :chart-labels="chartLabels" />
    </div>
  </div>
</template>

<script>
import SampleChart from "./SampleChart.vue";

export default {
  components: { SampleChart },
  data() {
    return {
      chartData: [],
      chartLabels: [],
    };
  },
  async beforeMount() {
    this.getTimelineData();
  },
  methods: {
    getTimelineData: function () {
      fetch("http://localhost:8080/sample.json")
        .then((res) => res.json())
        .then((data) => {
          data.data.forEach((el) => {
            this.chartData.push(el.value);
            this.chartLabels.push(el.timestamp);
          });
        });
    },
  },
};
</script>

Package.json dependencies

"dependencies": {
    "@j-t-mcc/vue3-chartjs": "^1.1.2",
    "bootstrap": "^5.0.2",
    "chart.js": "^3.3.2",
    "chartjs-adapter-date-fns": "^2.0.0",
    "core-js": "^3.6.5",
    "date-fns": "^2.23.0",
    "leaflet": "^1.7.1",
    "vue": "^3.1.5"
  }

The Error Message

Uncaught (in promise) RangeError: Maximum call stack size exceeded
    at Object.get (reactivity.esm-bundler.js?a1e9:231)
    at toRaw (reactivity.esm-bundler.js?a1e9:743)
    at Proxy.instrumentations.<computed> (reactivity.esm-bundler.js?a1e9:223)
    at Proxy.value (helpers.segment.js?dd3d:1531)
    at Proxy.instrumentations.<computed> (reactivity.esm-bundler.js?a1e9:223)
    at Proxy.value (helpers.segment.js?dd3d:1531)
    at Proxy.instrumentations.<computed> (reactivity.esm-bundler.js?a1e9:223)
    at Proxy.value (helpers.segment.js?dd3d:1531)
    at Proxy.instrumentations.<computed> (reactivity.esm-bundler.js?a1e9:223)
    at Proxy.value (helpers.segment.js?dd3d:1531)

Sample method without fetch that worked fine

getTestData: function () {
      var labels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
      var values = [10, 25, 39, 55, 90, 202, 304, 202, 105, 33, 44, 95, 20, 39, 90];
      labels.forEach((el) => {
        this.chartLabels.push(el);
      });
      values.forEach((el) => {
        this.chartData.push(el);
      });
    },

Json data sample

{
  "data": [
    {
      "timestamp": 1627382793000,
      "value": 121
    },
    {
      "timestamp": 1627383698000,
      "value": 203
    },
    {
      "timestamp": 1627387917000,
      "value": 15
    }
  ]
}

2个回答

添加一个带有 ready 属性的简单 v-if 即可,当我们完成推送数据的 foreach 时,我们会将其变为 true,

问题出在您的 SampleChart.vue 组件上,您在设置中制作图表数据,因此当数据更改时,sampleChart 在任何情况下都不会更改,它已经计算好了。 您可以了解有关 computed ref/reactive 的更多信息>

Houssem
2021-08-03

虽然 Hossem 的答案适用于第一次渲染,但是当您添加新数据时图表仍不会更新。

奇怪的是,将 Vue 版本从 3.1.5 降级到 3.1.4 最终解决了该问题。

pandaseatpotatos
2021-08-04